diff --git a/vetti-admin/src/main/java/com/vetti/socket/agents/ElevenLabsAgentClient.java b/vetti-admin/src/main/java/com/vetti/socket/agents/ElevenLabsAgentClient.java new file mode 100644 index 0000000..1bacb49 --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/socket/agents/ElevenLabsAgentClient.java @@ -0,0 +1,173 @@ +package com.vetti.socket.agents; + +import okhttp3.*; +import okio.ByteString; +import org.springframework.web.socket.BinaryMessage; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * + */ +public class ElevenLabsAgentClient extends TextWebSocketHandler{ + + // 存储Vue会话与ElevenLabs WebSocket的映射(多客户端隔离) + private static final Map SESSION_MAP = new ConcurrentHashMap<>(); + // ElevenLabs配置 + private static final String ELEVEN_LABS_API_KEY = "你的ElevenLabs API Key"; + private static final String AGENT_ID = "你的ElevenLabs Agent ID"; + private static final String ELEVEN_LABS_WSS_URL = "wss://api.elevenlabs.io/v1/agents/" + AGENT_ID + "/stream"; + // OkHttp客户端 + private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder() + .readTimeout(0, TimeUnit.MILLISECONDS) // WebSocket长连接取消读超时 + .build(); + + // ==================== 1. 处理Vue前端连接 ==================== + @Override + public void afterConnectionEstablished(WebSocketSession vueSession) throws Exception { + super.afterConnectionEstablished(vueSession); + System.out.println("Vue前端连接成功:" + vueSession.getId()); + + // 建立与ElevenLabs Agents的WSS连接 + buildElevenLabsWssConnection(vueSession); + } + + // ==================== 2. 处理Vue前端发送的文本消息(如语音指令、配置信息) ==================== + @Override + protected void handleTextMessage(WebSocketSession vueSession, TextMessage message) throws Exception { + super.handleTextMessage(vueSession, message); + System.out.println("接收Vue文本消息:" + message.getPayload()); + // 获取对应ElevenLabs WebSocket连接,转发消息 + WebSocket elevenLabsWs = SESSION_MAP.get(vueSession); + if (elevenLabsWs != null && elevenLabsWs.queueSize() == 0) { + elevenLabsWs.send(message.getPayload()); + System.out.println("转发文本消息到ElevenLabs成功"); + } + } + + // ==================== 3. 处理Vue前端发送的二进制消息(核心:语音流数据) ==================== + @Override + protected void handleBinaryMessage(WebSocketSession vueSession, BinaryMessage message) { + super.handleBinaryMessage(vueSession, message); + byte[] voiceData = message.getPayload().array(); + System.out.println("接收Vue语音流数据,字节长度:" + voiceData.length); + + // 获取对应ElevenLabs WebSocket连接,转发语音流(二进制) + WebSocket elevenLabsWs = SESSION_MAP.get(vueSession); + if (elevenLabsWs != null && elevenLabsWs.queueSize() == 0) { + elevenLabsWs.send(ByteString.of(voiceData)); + System.out.println("转发语音流到ElevenLabs成功"); + } + + // 释放二进制消息资源 +// message.isLast(); + } + + // ==================== 4. 处理Vue前端连接关闭 ==================== + @Override + public void afterConnectionClosed(WebSocketSession vueSession, org.springframework.web.socket.CloseStatus status) throws Exception { + super.afterConnectionClosed(vueSession, status); + System.out.println("Vue前端连接关闭:" + vueSession.getId() + ",原因:" + status.getReason()); + + // 关闭对应的ElevenLabs WSS连接 + WebSocket elevenLabsWs = SESSION_MAP.remove(vueSession); + if (elevenLabsWs != null) { + elevenLabsWs.close(1000, "Vue客户端断开连接"); + System.out.println("关闭ElevenLabs WSS连接成功"); + } + } + + // ==================== 5. 建立与ElevenLabs Agents的WSS连接 ==================== + private void buildElevenLabsWssConnection(WebSocketSession vueSession) { + // 1. 构建ElevenLabs WSS请求(携带认证头) + Request request = new Request.Builder() + .url(ELEVEN_LABS_WSS_URL) + .header("xi-api-key", ELEVEN_LABS_API_KEY) // 必选认证头 + .build(); + + // 2. 构建ElevenLabs WSS监听器(处理响应并回流到Vue) + WebSocketListener elevenLabsListener = new WebSocketListener() { + // ElevenLabs WSS连接建立 + @Override + public void onOpen(WebSocket webSocket, Response response) { + super.onOpen(webSocket, response); + System.out.println("与ElevenLabs Agents WSS连接成功"); + // 存储Vue会话与ElevenLabs WS的映射 + SESSION_MAP.put(vueSession, webSocket); + } + + // 接收ElevenLabs文本消息(如状态、错误提示),回流到Vue + @Override + public void onMessage(WebSocket webSocket, String text) { + super.onMessage(webSocket, text); + System.out.println("接收ElevenLabs文本消息:" + text); + try { + // 回流到Vue前端 + if (vueSession.isOpen()) { + vueSession.sendMessage(new TextMessage(text)); + } + } catch (Exception e) { + System.err.println("回流文本消息到Vue失败:" + e.getMessage()); + } + } + + // 接收ElevenLabs二进制消息(核心:音频流响应),回流到Vue + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + super.onMessage(webSocket, bytes); + byte[] audioData = bytes.toByteArray(); + System.out.println("接收ElevenLabs音频流数据,字节长度:" + audioData.length); + try { + // 回流二进制音频流到Vue前端 + if (vueSession.isOpen()) { + vueSession.sendMessage(new BinaryMessage(audioData)); + } + } catch (Exception e) { + System.err.println("回流音频流到Vue失败:" + e.getMessage()); + } + } + + // ElevenLabs WSS连接关闭 + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + super.onClosed(webSocket, code, reason); + System.out.println("ElevenLabs WSS连接关闭:" + reason + ",状态码:" + code); + // 移除映射,关闭Vue连接 + SESSION_MAP.remove(vueSession); + try { + if (vueSession.isOpen()) { + vueSession.close(org.springframework.web.socket.CloseStatus.NORMAL); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // ElevenLabs WSS连接异常 + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + super.onFailure(webSocket, t, response); + System.err.println("ElevenLabs WSS连接异常:" + t.getMessage()); + // 移除映射,关闭Vue连接 + SESSION_MAP.remove(vueSession); + try { + if (vueSession.isOpen()) { + vueSession.close(org.springframework.web.socket.CloseStatus.SERVER_ERROR); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + // 3. 建立ElevenLabs WSS连接 + OK_HTTP_CLIENT.newWebSocket(request, elevenLabsListener); + } +} + + diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/ai/AiCommonController.java b/vetti-admin/src/main/java/com/vetti/web/controller/ai/AiCommonController.java index 493fafc..fb59f37 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/ai/AiCommonController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/ai/AiCommonController.java @@ -9,10 +9,7 @@ import com.vetti.common.core.controller.BaseController; import com.vetti.common.core.domain.AjaxResult; import com.vetti.common.core.domain.R; import com.vetti.common.core.domain.dto.RealtimeClientSecretDto; -import com.vetti.common.enums.MinioBucketNameEnum; -import com.vetti.common.utils.readFile.FileContentUtil; import com.vetti.web.service.ICommonService; -import io.minio.GetObjectArgs; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -21,10 +18,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; - /** * AI 共通测试接口处理 * 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 new file mode 100644 index 0000000..200127c --- /dev/null +++ b/vetti-admin/src/main/java/com/vetti/web/controller/ai/HotakeAiCommonToolsController.java @@ -0,0 +1,85 @@ +package com.vetti.web.controller.ai; + +import com.vetti.common.core.controller.BaseController; +import com.vetti.common.core.domain.R; +import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; +import com.vetti.hotake.domain.dto.HotakeCvOptimizeDto; +import com.vetti.hotake.domain.dto.HotakeInitialQuestionEliminationScoreDto; +import com.vetti.hotake.domain.dto.HotakeJobDescriptionGeneratorDto; +import com.vetti.hotake.domain.vo.HotakeInitialScreeningQuestionsVo; +import com.vetti.hotake.domain.vo.HotakeJobDescriptionGeneratorVo; +import com.vetti.hotake.domain.vo.HotakeResumeJobMatchingScoreVo; +import com.vetti.hotake.service.IHotakeAiCommonToolsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * AI共通工具 信息Controller + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Api(tags ="AI共通工具信息") +@RestController +@RequestMapping("/hotake/aiCommonTools") +public class HotakeAiCommonToolsController extends BaseController { + + @Autowired + private IHotakeAiCommonToolsService hotakeAiCommonToolsService; + + + /** + * 职位描述生成器 + */ + @ApiOperation("职位描述生成器") + @PostMapping(value = "/jobDescriptionGenerator") + public R handleJobDescriptionGenerator(@RequestBody HotakeJobDescriptionGeneratorVo jobDescriptionGeneratorVo) + { + return R.ok(hotakeAiCommonToolsService.getJobDescriptionGenerator(jobDescriptionGeneratorVo.getRoleId())); + } + + /** + * 初筛问题生成 + */ + @ApiOperation("初筛问题生成") + @PostMapping(value = "/initialScreeningQuestionsGenerator") + public R> handleInitialScreeningQuestions(@RequestBody HotakeInitialScreeningQuestionsVo questionsVo) + { + return R.ok(hotakeAiCommonToolsService.getInitialScreeningQuestionsGenerator(questionsVo)); + } + + /** + * 简历岗位匹配度评分 + */ + @ApiOperation("简历岗位匹配度评分") + @GetMapping(value = "/resumeJobMatchingScore") + public R handleResumeJobMatchingScore(@RequestBody HotakeResumeJobMatchingScoreVo scoreVo) + { + return R.ok(hotakeAiCommonToolsService.getResumeJobMatchingScore(scoreVo)); + } + + /** + * 简历分析优化器 + */ + @ApiOperation("简历分析优化器") + @GetMapping(value = "/resumeAnalysisOptimizer") + public R handleResumeAnalysisOptimizer() + { + return R.ok(hotakeAiCommonToolsService.getResumeAnalysisOptimizer("")); + } + + /** + * 初步筛选问题淘汰评分 + */ + @ApiOperation("初步筛选问题淘汰评分") + @GetMapping(value = "/initialQuestionEliminationScore") + public R handleInitialQuestionEliminationScore() + { + return R.ok(hotakeAiCommonToolsService.getInitialQuestionEliminationScore(null)); + } + +} diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeCvInfoController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeCvInfoController.java index 2899393..24d1a6a 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeCvInfoController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeCvInfoController.java @@ -12,6 +12,7 @@ import com.vetti.hotake.domain.HotakeCvInfo; import com.vetti.hotake.service.IHotakeCvInfoService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -60,7 +61,7 @@ public class HotakeCvInfoController extends BaseController */ @ApiOperation("获取简历信息详细信息") @GetMapping(value = "/{id}") - public R getInfo(@PathVariable("id") Long id) + public R getInfo(@ApiParam("简历ID") @PathVariable("id") Long id) { return R.ok(hotakeCvInfoService.selectHotakeCvInfoById(id),""); } diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeInitialScreeningQuestionsInfoController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeInitialScreeningQuestionsInfoController.java index 34fa70d..153d1b6 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeInitialScreeningQuestionsInfoController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeInitialScreeningQuestionsInfoController.java @@ -7,6 +7,7 @@ import com.vetti.common.core.page.TableDataInfo; import com.vetti.common.core.page.TableWebDataInfo; import com.vetti.common.enums.BusinessType; import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; +import com.vetti.hotake.domain.vo.HotakeInitialScreeningQuestionsInfoVo; import com.vetti.hotake.service.IHotakeInitialScreeningQuestionsInfoService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -94,4 +95,16 @@ public class HotakeInitialScreeningQuestionsInfoController extends BaseControlle { return R.ok(hotakeInitialScreeningQuestionsInfoService.deleteHotakeInitialScreeningQuestionsInfoByIds(ids)); } + + /** + * 新增初步筛选问题信息 + */ + @ApiOperation("批量新增初步筛选问题信息") + @Log(title = "批量新增初步筛选问题信息", businessType = BusinessType.INSERT) + @PostMapping("/batchAdd") + public R batchAdd(@RequestBody HotakeInitialScreeningQuestionsInfoVo questionsInfoVo) + { + hotakeInitialScreeningQuestionsInfoService.batchInsertHotakeInitialScreeningQuestionsInfo(questionsInfoVo); + return R.ok(); + } } diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java index 1a2a8ec..fc7e24b 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeMeetingCalendarInfoController.java @@ -7,6 +7,7 @@ import com.vetti.common.core.page.TableDataInfo; import com.vetti.common.core.page.TableWebDataInfo; import com.vetti.common.enums.BusinessType; import com.vetti.hotake.domain.HotakeMeetingCalendarInfo; +import com.vetti.hotake.domain.dto.HotakeMeetingCalendarDataDto; import com.vetti.hotake.domain.vo.HotakeMeetingCalendarVo; import com.vetti.hotake.service.IHotakeMeetingCalendarInfoService; import io.swagger.annotations.Api; @@ -47,12 +48,12 @@ public class HotakeMeetingCalendarInfoController extends BaseController /** * 查询会议日历记录主列表(无分页) */ - @ApiOperation("查询会议日历记录列表(无分页)") + @ApiOperation("候选人-查询会议日历记录列表(无分页)") @GetMapping("/getList") public R> list(HotakeMeetingCalendarInfo hotakeMeetingCalendarInfo) { - List list = hotakeMeetingCalendarInfoService.selectHotakeMeetingCalendarInfoList(hotakeMeetingCalendarInfo); - return R.ok(list); + List list = hotakeMeetingCalendarInfoService.selectHotakeMeetingCalendarInfoCandidateList(hotakeMeetingCalendarInfo); + return R.ok(list,""); } /** @@ -110,4 +111,15 @@ public class HotakeMeetingCalendarInfoController extends BaseController hotakeMeetingCalendarInfoService.saveHotakeMeetingCalendarInfo(calendarVo); return R.ok(); } + + /** + * 查询当前候选者会议日历数据 + */ + @ApiOperation("查询当前候选者会议日历数据") + @GetMapping("/getCandidateCalendarList") + public R> listCandidateAll() + { + List list = hotakeMeetingCalendarInfoService.selectHotakeMeetingCalendarDataDtoList(); + return R.ok(list,""); + } } diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java index 6cd38f7..3f54818 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java @@ -90,7 +90,7 @@ public class HotakeRolesApplyInfoController extends BaseController * 删除候选人岗位申请信息 */ @ApiOperation("删除候选人岗位申请信息") - @Log(title = "候选人岗位申请信息", businessType = BusinessType.DELETE) + @Log(title = "删除候选人岗位申请信息", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public R remove(@PathVariable Long[] ids) { diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java b/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java index 1281622..fb90fd5 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/system/SysLoginController.java @@ -2,6 +2,8 @@ package com.vetti.web.controller.system; import java.util.*; +import com.vetti.common.core.domain.R; +import com.vetti.common.core.domain.dto.LoginDto; import com.vetti.common.utils.MessageUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -58,11 +60,11 @@ public class SysLoginController */ @ApiOperation("登录方法") @PostMapping("/login") - public AjaxResult login(@RequestBody LoginBody loginBody) + public R login(@RequestBody LoginBody loginBody) { - AjaxResult ajax = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), + LoginDto loginDto = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid()); - return ajax; + return R.ok(loginDto,""); } /** diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/system/SysProfileController.java b/vetti-admin/src/main/java/com/vetti/web/controller/system/SysProfileController.java index fbdbf6a..cb8fa69 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/system/SysProfileController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/system/SysProfileController.java @@ -123,6 +123,7 @@ public class SysProfileController extends BaseController //个人展示数据存储 currentUser.setBestSideJson(JSONUtil.toJsonStr(user.getBestSideDtoList())); } + currentUser.setUserOperStatus(user.getUserOperStatus()); currentUser.setSteps(user.getSteps()); if (userService.updateUserProfile(currentUser) > 0) { diff --git a/vetti-admin/src/main/resources/application-druid.yml b/vetti-admin/src/main/resources/application-druid.yml index 96a1507..8ed3a34 100644 --- a/vetti-admin/src/main/resources/application-druid.yml +++ b/vetti-admin/src/main/resources/application-druid.yml @@ -173,6 +173,11 @@ chatGpt: modelQuestion: ft:gpt-4o-mini-2024-07-18:vetti:interview-corpus:ChvLmzLu modelCV: ft:gpt-3.5-turbo-0125:vetti:vetti-resume-full:CYT0C8JG modelJxCv: gpt-4o-mini + modelJd: gpt-4o-mini + modelIsq: ft:gpt-4o-mini-2024-07-18:vetti:question-gen-expanded:CncFPHBB + modelRoleCv: ft:gpt-4o-mini-2024-07-18:vetti:resume-scoring-v2:CnbgEHQQ + modelCvJx: gpt-4o-mini + modelCbqpf: 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 96a1507..8ed3a34 100644 --- a/vetti-admin/target/classes/application-druid.yml +++ b/vetti-admin/target/classes/application-druid.yml @@ -173,6 +173,11 @@ chatGpt: modelQuestion: ft:gpt-4o-mini-2024-07-18:vetti:interview-corpus:ChvLmzLu modelCV: ft:gpt-3.5-turbo-0125:vetti:vetti-resume-full:CYT0C8JG modelJxCv: gpt-4o-mini + modelJd: gpt-4o-mini + modelIsq: ft:gpt-4o-mini-2024-07-18:vetti:question-gen-expanded:CncFPHBB + modelRoleCv: ft:gpt-4o-mini-2024-07-18:vetti:resume-scoring-v2:CnbgEHQQ + modelCvJx: gpt-4o-mini + modelCbqpf: gpt-4o-mini role: system http: 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 1e95fe3..569a925 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 @@ -42,6 +42,21 @@ public class ChatGPTClient { @Value("${chatGpt.modelJxCv}") private String modelJxCv; + @Value("${chatGpt.modelJd}") + private String modelJd; + + @Value("${chatGpt.modelIsq}") + private String modelIsq; + + @Value("${chatGpt.modelRoleCv}") + private String modelRoleCv; + + @Value("${chatGpt.modelCvJx}") + private String modelCvJx; + + @Value("${chatGpt.modelCbqpf}") + private String modelCbqpf; + @Value("${chatGpt.role}") private String role; @@ -71,6 +86,16 @@ public class ChatGPTClient { resultText = sendMessage(promptText, model,objectMapper,client,role); }else if("JX".equals(type)){ resultText = sendMessage(promptText, modelJxCv,objectMapper,client,role); + }else if("JD".equals(type)){ + resultText = sendMessage(promptText, modelJd,objectMapper,client,role); + }else if("ISQ".equals(type)){ + resultText = sendMessage(promptText, modelIsq,objectMapper,client,role); + }else if("ROLECV".equals(type)){ + resultText = sendMessage(promptText, modelRoleCv,objectMapper,client,role); + }else if("CVJX".equals(type)){ + resultText = sendMessage(promptText, modelCvJx,objectMapper,client,role); + }else if("CBQPF".equals(type)){ + resultText = sendMessage(promptText, modelCbqpf,objectMapper,client,role); }else { resultText = sendMessage(promptText, modelQuestion,objectMapper,client,role); } diff --git a/vetti-common/src/main/java/com/vetti/common/core/domain/dto/LoginDto.java b/vetti-common/src/main/java/com/vetti/common/core/domain/dto/LoginDto.java new file mode 100644 index 0000000..1a8cc4f --- /dev/null +++ b/vetti-common/src/main/java/com/vetti/common/core/domain/dto/LoginDto.java @@ -0,0 +1,28 @@ +package com.vetti.common.core.domain.dto; + +import com.vetti.common.core.domain.entity.SysUser; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 系统登陆返回登陆对象 + * + * @author wangxiangshun + * @date 2025-10-29 + */ +@Data +@Accessors(chain = true) +public class LoginDto { + + + @ApiModelProperty("令牌") + private String token; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("用户信息对象") + private SysUser user; + +} diff --git a/vetti-common/src/main/java/com/vetti/common/core/domain/entity/SysUser.java b/vetti-common/src/main/java/com/vetti/common/core/domain/entity/SysUser.java index 219eab1..dcd7ecb 100644 --- a/vetti-common/src/main/java/com/vetti/common/core/domain/entity/SysUser.java +++ b/vetti-common/src/main/java/com/vetti/common/core/domain/entity/SysUser.java @@ -127,6 +127,9 @@ public class SysUser extends BaseEntity @ApiModelProperty("用户标识(1:新用户,2:老用户)") private String userFlag; + @ApiModelProperty("用户操作状态(1:初始化,2:已保存,3:已跳过)") + private String userOperStatus; + @ApiModelProperty("用户语音配置信息") private String userSetJson; @@ -496,6 +499,15 @@ public class SysUser extends BaseEntity this.jobTitle = jobTitle; } + + public String getUserOperStatus() { + return userOperStatus; + } + + public void setUserOperStatus(String userOperStatus) { + this.userOperStatus = userOperStatus; + } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/vetti-framework/src/main/java/com/vetti/framework/web/service/SysLoginService.java b/vetti-framework/src/main/java/com/vetti/framework/web/service/SysLoginService.java index 371ddca..5f55216 100644 --- a/vetti-framework/src/main/java/com/vetti/framework/web/service/SysLoginService.java +++ b/vetti-framework/src/main/java/com/vetti/framework/web/service/SysLoginService.java @@ -3,6 +3,7 @@ package com.vetti.framework.web.service; import javax.annotation.Resource; import com.vetti.common.core.domain.AjaxResult; +import com.vetti.common.core.domain.dto.LoginDto; import com.vetti.common.utils.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; @@ -64,9 +65,10 @@ public class SysLoginService * @param uuid 唯一标识 * @return 结果 */ - public AjaxResult login(String username, String password, String code, String uuid) + public LoginDto login(String username, String password, String code, String uuid) { - AjaxResult ajax = AjaxResult.success(); + LoginDto loginDto = new LoginDto(); + // 验证码校验 // validateCaptcha(username, code, uuid); // 登录前置校验 @@ -101,9 +103,12 @@ public class SysLoginService LoginUser loginUser = (LoginUser) authentication.getPrincipal(); recordLoginInfo(loginUser.getUserId()); // 生成token - ajax.put(Constants.TOKEN, tokenService.createToken(loginUser)); - ajax.put("userId",loginUser.getUserId()); - return ajax; + loginDto.setToken(tokenService.createToken(loginUser)); + loginDto.setUserId(loginUser.getUserId()); + SysUser user = userService.selectUserById(loginUser.getUserId()); + loginDto.setUser(user); + + return loginDto; } diff --git a/vetti-framework/src/main/java/com/vetti/framework/web/service/SysRegisterService.java b/vetti-framework/src/main/java/com/vetti/framework/web/service/SysRegisterService.java index 4482dff..7031625 100644 --- a/vetti-framework/src/main/java/com/vetti/framework/web/service/SysRegisterService.java +++ b/vetti-framework/src/main/java/com/vetti/framework/web/service/SysRegisterService.java @@ -82,6 +82,8 @@ public class SysRegisterService { throw new ServiceException(MessageUtils.messageCustomize("systemSysRegisterService10005")); } else { sysUser.setUserFlag(UserFlagEnum.FLAG_1.getCode()); + //操作状态初始化 + sysUser.setUserOperStatus("1"); sysUser.setSysUserType(registerBody.getSysUserType()); // sysUser.setNickName(username); sysUser.setPwdUpdateDate(DateUtils.getNowDate()); diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeCvInfo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeCvInfo.java index e3f337a..2c22f9d 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeCvInfo.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeCvInfo.java @@ -1,6 +1,7 @@ package com.vetti.hotake.domain; import com.vetti.hotake.domain.dto.HotakeCvInfoDto; +import com.vetti.hotake.domain.dto.HotakeCvOptimizeDto; import lombok.Data; import lombok.experimental.Accessors; import io.swagger.annotations.ApiModelProperty; @@ -80,4 +81,16 @@ public class HotakeCvInfo extends BaseEntity @ApiModelProperty("简历评分") private String score; + @ApiModelProperty("简历分析结果数据存储") + private String cvOptimizeJson; + + @ApiModelProperty("文本修正的数量") + private Integer textCorrectionsNums; + + @ApiModelProperty("逻辑修正的数量") + private Integer logicCorrectionsNum; + + @ApiModelProperty("简历分析结果数据") + private HotakeCvOptimizeDto cvOptimizeDto; + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeMeetingCalendarInfo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeMeetingCalendarInfo.java index 4447ebc..e905fd2 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeMeetingCalendarInfo.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeMeetingCalendarInfo.java @@ -59,7 +59,7 @@ public class HotakeMeetingCalendarInfo extends BaseEntity private String messageVia; /** 状态(0 取消,1 正常) */ - @ApiModelProperty("状态(0 取消,1 正常)") + @ApiModelProperty("状态(0 取消,1 正常,2 已完成面试)") private String status; @ApiModelProperty("岗位基本信息") @@ -69,4 +69,8 @@ public class HotakeMeetingCalendarInfo extends BaseEntity private List calendarDetails; + @ApiModelProperty("会议ID数据集合-查询使用") + private List meetingIds; + + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCvOptimizeDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCvOptimizeDto.java new file mode 100644 index 0000000..80c77ef --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCvOptimizeDto.java @@ -0,0 +1,30 @@ +package com.vetti.hotake.domain.dto; + +import com.vetti.hotake.domain.dto.VcDto.*; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 简历优化器 返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class HotakeCvOptimizeDto { + + @ApiModelProperty("分析总结") + private CvAnalysisSummaryDto analysisSummary; + @ApiModelProperty("文本修正(文字、语法等错误)") + private CvTextCorrectionsDto textCorrections; + @ApiModelProperty("逻辑修正") + private CvLogicCorrectionsDto logicCorrections; + @ApiModelProperty("优化建议") + private CvOptimizationSuggestionsDto optimizationSuggestions; + @ApiModelProperty("行动计划") + private CvActionPlanDto actionPlan; + @ApiModelProperty("预期改进效果") + private CvEstimatedImprovementDto estimatedImprovement; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeInitialQuestionEliminationScoreDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeInitialQuestionEliminationScoreDto.java new file mode 100644 index 0000000..2d30694 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeInitialQuestionEliminationScoreDto.java @@ -0,0 +1,22 @@ +package com.vetti.hotake.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 初步筛选问题淘汰评分 返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class HotakeInitialQuestionEliminationScoreDto { + + @ApiModelProperty("评分") + private String score; + + @ApiModelProperty("描述") + private String evaluate; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeJobDescriptionGeneratorDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeJobDescriptionGeneratorDto.java new file mode 100644 index 0000000..1f5803c --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeJobDescriptionGeneratorDto.java @@ -0,0 +1,41 @@ +package com.vetti.hotake.domain.dto; + +import com.vetti.hotake.domain.dto.roleDto.NiceToHaveSkillsDto; +import com.vetti.hotake.domain.dto.roleDto.RequiredSkillsDto; +import com.vetti.hotake.domain.dto.roleDto.ResponsibilitiesDto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 岗位-职位描述 返回信息 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class HotakeJobDescriptionGeneratorDto { + + /** 关于职位 */ + @ApiModelProperty("关于职位") + private String aboutRole; + + /** 职责 */ + @ApiModelProperty("职责") + private List responsibilitiesList; + + + @ApiModelProperty("岗位所需技能信息数据集合") + private List skillsDtoList; + + + @ApiModelProperty("岗位加分技能信息数据集合") + private List haveSkillsDtoList; + + + + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeMeetingCalendarDataDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeMeetingCalendarDataDto.java new file mode 100644 index 0000000..7768ff5 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeMeetingCalendarDataDto.java @@ -0,0 +1,30 @@ +package com.vetti.hotake.domain.dto; + +import com.vetti.common.annotation.Excel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 会议日历返回数据 实体类对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class HotakeMeetingCalendarDataDto { + + /** 会议日期 */ + @ApiModelProperty("会议日期(年月日)") + @Excel(name = "会议日期") + private String meetingDate; + + @ApiModelProperty("是否有会议(0:无,1:有会议)") + private String meetingFlag; + + @ApiModelProperty("当前日期对应的会议数量") + private Integer nums; + + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvActionPlanDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvActionPlanDto.java new file mode 100644 index 0000000..849868a --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvActionPlanDto.java @@ -0,0 +1,27 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-行动计划 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvActionPlanDto { + + @ApiModelProperty("立即修正项,优先级最高 ") + private List immediateFixes; + + @ApiModelProperty("内容改进项,中期执行 ") + private List contentImprovements; + + @ApiModelProperty("战略性提升项,长期优化 ") + private List strategicEnhancements; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvAnalysisSummaryDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvAnalysisSummaryDto.java new file mode 100644 index 0000000..2522f04 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvAnalysisSummaryDto.java @@ -0,0 +1,33 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-分析总结 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvAnalysisSummaryDto { + + @ApiModelProperty("简历综合评分 (0-100) ") + private String overallScore; + + @ApiModelProperty("主要优势列表,突出候选人核心竞争力 ") + private List mainStrengths; + + + @ApiModelProperty("关键问题列表,需要优先解决的问题 ") + private List criticalIssues; + + @ApiModelProperty("改进潜力:high/medium/low") + private String improvementPotential; + + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvCareerProgressionDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvCareerProgressionDto.java new file mode 100644 index 0000000..ce8f4cb --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvCareerProgressionDto.java @@ -0,0 +1,26 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 简历-优化器-职业发展逻辑 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvCareerProgressionDto { + + @ApiModelProperty("问题") + private String issue; + + @ApiModelProperty("详细信息") + private String details; + + @ApiModelProperty("建议") + private String suggestion; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvEstimatedImprovementDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvEstimatedImprovementDto.java new file mode 100644 index 0000000..89e7107 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvEstimatedImprovementDto.java @@ -0,0 +1,29 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 简历-优化器-预期改进效果 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvEstimatedImprovementDto { + + @ApiModelProperty("当前ATS系统评分 (0-100) ") + private String currentAtsScore; + + @ApiModelProperty("优化后预期ATS评分 ") + private String potentialAtsScore; + + @ApiModelProperty("对招聘官的吸引力提升程度") + private String recruiterAppeal; + + @ApiModelProperty("获得面试机会的概率提升") + private String interviewProbability; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvFormattingIssuesDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvFormattingIssuesDto.java new file mode 100644 index 0000000..8973184 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvFormattingIssuesDto.java @@ -0,0 +1,28 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-格式错误 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvFormattingIssuesDto { + + @ApiModelProperty("问题") + private String issue; + + @ApiModelProperty("修正建议") + private String suggestion; + + @ApiModelProperty("错误位置") + private List locations; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvGrammarErrorsDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvGrammarErrorsDto.java new file mode 100644 index 0000000..ca5610b --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvGrammarErrorsDto.java @@ -0,0 +1,30 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 简历-优化器-语法错误 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvGrammarErrorsDto { + + @ApiModelProperty("原始数据") + private String original; + + @ApiModelProperty("修正数据") + private String corrected; + + @ApiModelProperty("错误位置") + private String location; + + @ApiModelProperty("解释说明") + private String explanation; + + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvKeywordOptimizationDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvKeywordOptimizationDto.java new file mode 100644 index 0000000..0d36874 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvKeywordOptimizationDto.java @@ -0,0 +1,27 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-关键词优化 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvKeywordOptimizationDto { + + @ApiModelProperty("缺少关键字") + private List missingKeywords; + + @ApiModelProperty("行业术语") + private List industryTerms; + + @ApiModelProperty("ats关键字") + private List atsKeywords; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvLogicCorrectionsDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvLogicCorrectionsDto.java new file mode 100644 index 0000000..72c8180 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvLogicCorrectionsDto.java @@ -0,0 +1,27 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-逻辑修正 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvLogicCorrectionsDto { + + @ApiModelProperty("时间线冲突列表数据集合") + private List timelineConflicts; + + @ApiModelProperty("职业发展逻辑数据集合") + private List careerProgressionDtos; + + @ApiModelProperty("技能经验匹配数据集合") + private List skillExperienceMismatchDtos; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvOptimizationSuggestionsDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvOptimizationSuggestionsDto.java new file mode 100644 index 0000000..dc56a8a --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvOptimizationSuggestionsDto.java @@ -0,0 +1,31 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-优化建议 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvOptimizationSuggestionsDto { + + @ApiModelProperty("个人简介优化") + private CvPersonalSummaryDto personalSummary; + + @ApiModelProperty("工作经历优化建议") + private List workExperienceDtoList; + + @ApiModelProperty("技能部分优化") + private CvSkillsSectionDto skillsSection; + + @ApiModelProperty("关键词优化") + private CvKeywordOptimizationDto keywordOptimization; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvPersonalSummaryDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvPersonalSummaryDto.java new file mode 100644 index 0000000..33b9e9c --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvPersonalSummaryDto.java @@ -0,0 +1,28 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-个人总结 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvPersonalSummaryDto { + + @ApiModelProperty("当前问题列表") + private List currentIssues; + + @ApiModelProperty("优化后的个人简介") + private String optimizedVersion; + + @ApiModelProperty("关键改进点") + private List keyImprovements; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSkillExperienceMismatchDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSkillExperienceMismatchDto.java new file mode 100644 index 0000000..371d9e8 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSkillExperienceMismatchDto.java @@ -0,0 +1,25 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 简历-优化器-技能经验匹配 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvSkillExperienceMismatchDto { + + @ApiModelProperty("技能") + private String skill; + + @ApiModelProperty("问题") + private String issue; + + @ApiModelProperty("建议") + private String suggestion; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSkillsSectionDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSkillsSectionDto.java new file mode 100644 index 0000000..9c63c5e --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSkillsSectionDto.java @@ -0,0 +1,26 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-技能部分优化 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvSkillsSectionDto { + + @ApiModelProperty("当前问题") + private List currentIssues; + + @ApiModelProperty("建议结构") + private CvSuggestedStructureDto suggestedStructureDto; + + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSpellingErrorsDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSpellingErrorsDto.java new file mode 100644 index 0000000..919be95 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSpellingErrorsDto.java @@ -0,0 +1,25 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 简历-优化器-识别拼写错误 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvSpellingErrorsDto { + + @ApiModelProperty("原始数据") + private String original; + + @ApiModelProperty("修正数据") + private String corrected; + + @ApiModelProperty("错误位置") + private String location; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSuggestedStructureDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSuggestedStructureDto.java new file mode 100644 index 0000000..a706c42 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvSuggestedStructureDto.java @@ -0,0 +1,27 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-建议结构 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvSuggestedStructureDto { + + @ApiModelProperty("核心技能") + private List coreSkills; + + @ApiModelProperty("技术技能") + private List technicalSkills; + + @ApiModelProperty("认证") + private List certifications; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvTextCorrectionsDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvTextCorrectionsDto.java new file mode 100644 index 0000000..7ff0f92 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvTextCorrectionsDto.java @@ -0,0 +1,27 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-文本修正(文字、语法等错误) -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvTextCorrectionsDto { + + @ApiModelProperty("识别拼写错误数据集合") + private List spellingErrors; + + @ApiModelProperty("语法错误数据集合") + private List grammarErrors; + + @ApiModelProperty("格式错误数据集合") + private List formattingIssues; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvTimelineConflictsDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvTimelineConflictsDto.java new file mode 100644 index 0000000..b4d6027 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvTimelineConflictsDto.java @@ -0,0 +1,25 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 简历-优化器-检查时间线冲突 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvTimelineConflictsDto { + + @ApiModelProperty("冲突类型 ") + private String conflict; + + @ApiModelProperty("冲突详情 ") + private String details; + + @ApiModelProperty("解决建议 ") + private String suggestion; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvWorkExperienceDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvWorkExperienceDto.java new file mode 100644 index 0000000..65296f9 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/VcDto/CvWorkExperienceDto.java @@ -0,0 +1,30 @@ +package com.vetti.hotake.domain.dto.VcDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 简历-优化器-工作经验 -返回对象 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class CvWorkExperienceDto { + + @ApiModelProperty("职位名称") + private String position; + + @ApiModelProperty("当前描述") + private String currentDescription; + + @ApiModelProperty("优化后描述") + private String optimizedDescription; + + @ApiModelProperty("改进要点") + private List improvements; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/roleDto/ResponsibilitiesDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/roleDto/ResponsibilitiesDto.java new file mode 100644 index 0000000..b1a5982 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/roleDto/ResponsibilitiesDto.java @@ -0,0 +1,20 @@ +package com.vetti.hotake.domain.dto.roleDto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 岗位-职责信息 返回信息 + * + * @author wangxiangshun + * @date 2025-11-30 + */ +@Data +@Accessors(chain = true) +public class ResponsibilitiesDto { + + /** 职责 */ + @ApiModelProperty("职责") + private String responsibilities; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialQuestionEliminationScoreVo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialQuestionEliminationScoreVo.java new file mode 100644 index 0000000..c029eb7 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialQuestionEliminationScoreVo.java @@ -0,0 +1,32 @@ +package com.vetti.hotake.domain.vo; + +import com.vetti.common.annotation.Excel; +import com.vetti.hotake.domain.HotakeInitScreQuestionsReplyRecordInfo; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 岗位-初步筛选问题淘汰评分 对象 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Data +@Accessors(chain = true) +public class HotakeInitialQuestionEliminationScoreVo { + + @ApiModelProperty("岗位名称") + private String roleName; + + /** 岗位ID */ + @ApiModelProperty("岗位ID") + @Excel(name = "岗位ID") + private Long roleId; + + @ApiModelProperty("初步筛选问题回答记录数据集合") + private List initScreQuestionsReplyRecordInfoList; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialScreeningQuestionsInfoVo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialScreeningQuestionsInfoVo.java new file mode 100644 index 0000000..e274912 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialScreeningQuestionsInfoVo.java @@ -0,0 +1,25 @@ +package com.vetti.hotake.domain.vo; + +import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 岗位-初筛问题 对象 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Data +@Accessors(chain = true) +public class HotakeInitialScreeningQuestionsInfoVo { + + @ApiModelProperty("岗位ID") + private Long roleId; + + @ApiModelProperty("初步筛选问题数据集合") + private List questionsInfoList; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialScreeningQuestionsVo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialScreeningQuestionsVo.java new file mode 100644 index 0000000..a2aa843 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeInitialScreeningQuestionsVo.java @@ -0,0 +1,19 @@ +package com.vetti.hotake.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 岗位-初筛问题 对象 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Data +@Accessors(chain = true) +public class HotakeInitialScreeningQuestionsVo { + + @ApiModelProperty("岗位ID") + private Long roleId; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeJobDescriptionGeneratorVo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeJobDescriptionGeneratorVo.java new file mode 100644 index 0000000..4d9b184 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeJobDescriptionGeneratorVo.java @@ -0,0 +1,28 @@ +package com.vetti.hotake.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 岗位-职位描述生成器 对象 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Data +@Accessors(chain = true) +public class HotakeJobDescriptionGeneratorVo { + + @ApiModelProperty("岗位ID") + private Long roleId; + +// @ApiModelProperty("岗位名") +// private String jobTitle; +// +// @ApiModelProperty("行业领域-岗位类型") +// private String industry; +// +// @ApiModelProperty("关键技能或经验要求") +// private String coreRequirements; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeResumeJobMatchingScoreVo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeResumeJobMatchingScoreVo.java new file mode 100644 index 0000000..b4d41ff --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeResumeJobMatchingScoreVo.java @@ -0,0 +1,38 @@ +package com.vetti.hotake.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 岗位-简历岗位匹配度评分 对象 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Data +@Accessors(chain = true) +public class HotakeResumeJobMatchingScoreVo { + + @ApiModelProperty("岗位名") + private String jobTitle; + @ApiModelProperty("岗位描述") + private String jobDescription; + @ApiModelProperty("主要职责") + private String keyResponsibilities; + @ApiModelProperty("任职要求") + private String jobRequirements; + @ApiModelProperty("个人信息") + private String personalInformation; + @ApiModelProperty("工作经历") + private String workHistory; + @ApiModelProperty("项目经验") + private String projectExperience; + @ApiModelProperty("技能清单") + private String skillsList; + @ApiModelProperty("教育背景") + private String educationalBackground; + @ApiModelProperty("其他相关信息") + private String otherRelevantInformation; + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeInitialScreeningQuestionsInfoMapper.java b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeInitialScreeningQuestionsInfoMapper.java index 5ca7f9c..606dfb9 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeInitialScreeningQuestionsInfoMapper.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/mapper/HotakeInitialScreeningQuestionsInfoMapper.java @@ -51,6 +51,15 @@ public interface HotakeInitialScreeningQuestionsInfoMapper */ public int deleteHotakeInitialScreeningQuestionsInfoById(Long id); + /** + * 删除初步筛选问题信息 + * + * @param roleId 岗位ID + * @return 结果 + */ + public int deleteHotakeInitialScreeningQuestionsInfoByRoleId(Long roleId); + + /** * 批量删除初步筛选问题信息 * 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 new file mode 100644 index 0000000..3a4d628 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAiCommonToolsService.java @@ -0,0 +1,52 @@ +package com.vetti.hotake.service; + +import com.vetti.hotake.domain.HotakeAiInterviewQuestionsInfo; +import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; +import com.vetti.hotake.domain.dto.HotakeCvOptimizeDto; +import com.vetti.hotake.domain.dto.HotakeInitialQuestionEliminationScoreDto; +import com.vetti.hotake.domain.dto.HotakeJobDescriptionGeneratorDto; +import com.vetti.hotake.domain.vo.HotakeInitialQuestionEliminationScoreVo; +import com.vetti.hotake.domain.vo.HotakeInitialScreeningQuestionsVo; +import com.vetti.hotake.domain.vo.HotakeResumeJobMatchingScoreVo; + +import java.util.List; + +/** + * AI共通工具信息Service接口 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +public interface IHotakeAiCommonToolsService { + + + /** + * 职位描述生成器 + **/ + public HotakeJobDescriptionGeneratorDto getJobDescriptionGenerator(Long roleId); + + + + /** + * 初筛问题生成 + **/ + public List getInitialScreeningQuestionsGenerator(HotakeInitialScreeningQuestionsVo questionsVo); + + + /** + * 简历岗位匹配度评分 + **/ + public String getResumeJobMatchingScore(HotakeResumeJobMatchingScoreVo scoreVo); + + /** + * 简历分析优化器 + **/ + public HotakeCvOptimizeDto getResumeAnalysisOptimizer(String cvConnect); + + + /** + * 初步筛选问题淘汰评分 + **/ + public HotakeInitialQuestionEliminationScoreDto getInitialQuestionEliminationScore(HotakeInitialQuestionEliminationScoreVo questionEliminationScoreVo); + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeInitialScreeningQuestionsInfoService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeInitialScreeningQuestionsInfoService.java index f036652..c081a5b 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeInitialScreeningQuestionsInfoService.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeInitialScreeningQuestionsInfoService.java @@ -2,6 +2,7 @@ package com.vetti.hotake.service; import java.util.List; import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; +import com.vetti.hotake.domain.vo.HotakeInitialScreeningQuestionsInfoVo; /** * 初步筛选问题信息Service接口 @@ -62,9 +63,9 @@ public interface IHotakeInitialScreeningQuestionsInfoService /** * 批量新增初步筛选问题信息 * - * @param hotakeInitialScreeningQuestionsInfoList 初步筛选问题信息列表 + * @param questionsInfoVo 初步筛选问题数据对象 * @return 结果 */ - public int batchInsertHotakeInitialScreeningQuestionsInfo(List hotakeInitialScreeningQuestionsInfoList); + public void batchInsertHotakeInitialScreeningQuestionsInfo(HotakeInitialScreeningQuestionsInfoVo questionsInfoVo); } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java index 5b8b620..516e255 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeMeetingCalendarInfoService.java @@ -2,6 +2,7 @@ package com.vetti.hotake.service; import java.util.List; import com.vetti.hotake.domain.HotakeMeetingCalendarInfo; +import com.vetti.hotake.domain.dto.HotakeMeetingCalendarDataDto; import com.vetti.hotake.domain.vo.HotakeMeetingCalendarVo; /** @@ -28,6 +29,16 @@ public interface IHotakeMeetingCalendarInfoService */ public List selectHotakeMeetingCalendarInfoList(HotakeMeetingCalendarInfo hotakeMeetingCalendarInfo); + + /** + * 查询会议日历记录主列表 + * + * @param hotakeMeetingCalendarInfo 会议日历记录主 + * @return 会议日历记录主集合 + */ + public List selectHotakeMeetingCalendarInfoCandidateList(HotakeMeetingCalendarInfo hotakeMeetingCalendarInfo); + + /** * 新增会议日历记录主 * @@ -78,4 +89,12 @@ public interface IHotakeMeetingCalendarInfoService public void saveHotakeMeetingCalendarInfo(HotakeMeetingCalendarVo calendarVo); + /** + * 查询当前候选者会议日历数据 + * + * @return 查询当前候选者会议日历数据 + */ + public List selectHotakeMeetingCalendarDataDtoList(); + + } 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 new file mode 100644 index 0000000..c5f8120 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAiCommonToolsServiceImpl.java @@ -0,0 +1,1146 @@ +package com.vetti.hotake.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.json.JSONUtil; +import com.vetti.common.ai.gpt.ChatGPTClient; +import com.vetti.common.core.service.BaseServiceImpl; +import com.vetti.hotake.domain.HotakeInitScreQuestionsReplyRecordInfo; +import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; +import com.vetti.hotake.domain.HotakeRolesInfo; +import com.vetti.hotake.domain.dto.AnswerOptionsDto; +import com.vetti.hotake.domain.dto.HotakeCvOptimizeDto; +import com.vetti.hotake.domain.dto.HotakeInitialQuestionEliminationScoreDto; +import com.vetti.hotake.domain.dto.HotakeJobDescriptionGeneratorDto; +import com.vetti.hotake.domain.dto.VcDto.*; +import com.vetti.hotake.domain.dto.roleDto.NiceToHaveSkillsDto; +import com.vetti.hotake.domain.dto.roleDto.RequiredSkillsDto; +import com.vetti.hotake.domain.dto.roleDto.ResponsibilitiesDto; +import com.vetti.hotake.domain.vo.HotakeInitialQuestionEliminationScoreVo; +import com.vetti.hotake.domain.vo.HotakeInitialScreeningQuestionsVo; +import com.vetti.hotake.domain.vo.HotakeResumeJobMatchingScoreVo; +import com.vetti.hotake.mapper.HotakeInitialScreeningQuestionsInfoMapper; +import com.vetti.hotake.mapper.HotakeRolesApplyInfoMapper; +import com.vetti.hotake.mapper.HotakeRolesInfoMapper; +import com.vetti.hotake.service.IHotakeAiCommonToolsService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * AI共通工具 信息Service业务层处理 + * + * @author wangxiangshun + * @date 2025-12-14 + */ +@Slf4j +@SuppressWarnings("all") +@Service +public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements IHotakeAiCommonToolsService +{ + + @Autowired + private HotakeRolesInfoMapper hotakeRolesInfoMapper; + + @Autowired + private HotakeRolesApplyInfoMapper hotakeRolesApplyInfoMapper; + + @Autowired + private HotakeInitialScreeningQuestionsInfoMapper hotakeInitialScreeningQuestionsInfoMapper; + + @Autowired + private ChatGPTClient chatGPTClient; + + + /** + * 职位描述生成器 + * @param roleId 岗位ID + * @param industry Industry sector 行业领域 + * @param coreRequirements Key skills or experience requirements 关键技能或经验要求 + * @return + */ + @Override + public HotakeJobDescriptionGeneratorDto getJobDescriptionGenerator(Long roleId) { + HotakeJobDescriptionGeneratorDto generatorDto = new HotakeJobDescriptionGeneratorDto(); + //根据岗位ID查询岗位基本信息 + HotakeRolesInfo rolesInfo = hotakeRolesInfoMapper.selectHotakeRolesInfoById(roleId); + String prompt = initializationJobDescriptionPrompt(rolesInfo.getRoleName(),rolesInfo.getRoleType(), + rolesInfo.getRequiredSkillsJson()); + List> list = new LinkedList(); + Map mapEntity = new HashMap<>(); + mapEntity.put("role", "system"); + mapEntity.put("content",prompt); + list.add(mapEntity); + String promptJson = JSONUtil.toJsonStr(list); + String resultStr = chatGPTClient.handleAiChat(promptJson,"JD"); + log.info("返回职位描述:{}",resultStr); + //开始解析职位描述详细信息,主要生成的数据为第二步中的必备技能和优先加分技能,第三步中的关于岗位和职责 + String resultJson = resultStr.replaceAll("```json","").replaceAll("```",""); + + Map dataMap = JSONUtil.toBean(resultJson,Map.class); + + Map aboutRoleMap = (Map) dataMap.get("job_description"); + String aboutRole = aboutRoleMap.get("overview").toString(); + generatorDto.setAboutRole(aboutRole); + + List keyResponsibilitiesList = (List)dataMap.get("key_responsibilities"); + List responsibilitiesList = new ArrayList<>(); + if(CollectionUtil.isNotEmpty(keyResponsibilitiesList)){ + for(Map map : keyResponsibilitiesList){ + ResponsibilitiesDto responsibilitiesDto = new ResponsibilitiesDto(); + responsibilitiesDto.setResponsibilities(map.get("responsibility").toString()); + responsibilitiesList.add(responsibilitiesDto); + } + } + generatorDto.setResponsibilitiesList(responsibilitiesList); + + + Map requirementsMap = (Map) dataMap.get("requirements"); + + List essentialList = (List)requirementsMap.get("essential"); + List skillsDtoList = new ArrayList<>(); + if(CollectionUtil.isNotEmpty(essentialList)){ + for(Map map : essentialList){ + RequiredSkillsDto skillsDto = new RequiredSkillsDto(); + skillsDto.setKeyValue(map.get("requirement").toString()); + skillsDtoList.add(skillsDto); + } + } + generatorDto.setSkillsDtoList(skillsDtoList); + + + List preferredList = (List)requirementsMap.get("preferred"); + List haveSkillsDtoList = new ArrayList<>(); + if(CollectionUtil.isNotEmpty(preferredList)){ + for(Map map : preferredList){ + NiceToHaveSkillsDto haveSkillsDto = new NiceToHaveSkillsDto(); + haveSkillsDto.setKeyValue(map.get("requirement").toString()); + haveSkillsDtoList.add(haveSkillsDto); + } + } + generatorDto.setHaveSkillsDtoList(haveSkillsDtoList); + + return generatorDto; + } + + /** + * 初筛问题生成 + * @return + */ + @Override + public List getInitialScreeningQuestionsGenerator(HotakeInitialScreeningQuestionsVo questionsVo) { + List questionsInfoList = new ArrayList<>(); + //根据岗位ID查询岗位基本信息 + HotakeRolesInfo rolesInfo = hotakeRolesInfoMapper.selectHotakeRolesInfoById(questionsVo.getRoleId()); + String prompt = initializationInitialScreeningQuestionsPrompt(rolesInfo.getRoleName(),rolesInfo.getAboutRole(), + rolesInfo.getResponsibilities()); + List> list = new LinkedList(); + Map mapEntity = new HashMap<>(); + mapEntity.put("role", "system"); + mapEntity.put("content",prompt); + list.add(mapEntity); + String promptJson = JSONUtil.toJsonStr(list); + String resultStr = chatGPTClient.handleAiChat(promptJson,"ISQ"); + String resultJson = resultStr.replaceAll("```json","").replaceAll("```",""); + log.info("初筛问题生成:{}",resultStr); + //筛选问题结构化处理-进行初始化问题解析处理 + Map dataMap = JSONUtil.toBean(resultJson,Map.class); + + List questionsList = (List)dataMap.get("questions"); + if(CollectionUtil.isNotEmpty(questionsList)){ + for(Map map : questionsList){ + HotakeInitialScreeningQuestionsInfo questionsInfo = new HotakeInitialScreeningQuestionsInfo(); + questionsInfo.setQuestionType(map.get("type").toString()); + questionsInfo.setQuestionTitle(map.get("question").toString()); + questionsInfo.setRequiredField("0"); + List optionsList = (List)map.get("options"); + List answerOptionsList = new ArrayList<>(); + if(CollectionUtil.isNotEmpty(optionsList)){ + for(String option : optionsList){ + AnswerOptionsDto answerOptionsDto = new AnswerOptionsDto(); + answerOptionsDto.setAnswers(option); + answerOptionsList.add(answerOptionsDto); + } + } + if(CollectionUtil.isNotEmpty(answerOptionsList)){ + questionsInfo.setAnswerOptions(JSONUtil.toJsonStr(answerOptionsList)); + questionsInfo.setAnswerOptionsList(answerOptionsList); + } + questionsInfoList.add(questionsInfo); + } + } + return questionsInfoList; + } + + /** + * 简历岗位匹配度评分 + * @return + */ + @Override + public String getResumeJobMatchingScore(HotakeResumeJobMatchingScoreVo scoreVo) { + //查询岗位信息 + String prompt = initializationResumeJobMatchingScorePrompt(scoreVo.getJobTitle(),scoreVo.getJobDescription(), + scoreVo.getKeyResponsibilities(),scoreVo.getJobRequirements(),scoreVo.getPersonalInformation(), + scoreVo.getWorkHistory(),scoreVo.getProjectExperience(),scoreVo.getSkillsList(), + scoreVo.getEducationalBackground(),scoreVo.getOtherRelevantInformation()); + + List> list = new LinkedList(); + Map mapEntity = new HashMap<>(); + mapEntity.put("role", "system"); + mapEntity.put("content",prompt); + list.add(mapEntity); + String promptJson = JSONUtil.toJsonStr(list); + String resultStr = chatGPTClient.handleAiChat(promptJson,"ROLECV"); + log.info("简历岗位匹配度评分:{}",resultStr); + + return ""; + } + + /** + * 简历分析优化器 + * @param cvConnect 简历内容 + * @return + */ + @Override + public HotakeCvOptimizeDto getResumeAnalysisOptimizer(String cvConnect) { + //传输简历内容,返回简历分析结果 + String prompt = initializationResumeAnalysisOptimizerPrompt(); + List> list = new LinkedList(); + Map mapEntity = new HashMap<>(); + mapEntity.put("role", "system"); + mapEntity.put("content",prompt); + list.add(mapEntity); + Map mapUserEntity = new HashMap<>(); + mapUserEntity.put("role", "user"); + mapUserEntity.put("content","请分析以下简历并提供优化建议:\\n\\n"+cvConnect); + list.add(mapUserEntity); + + String promptJson = JSONUtil.toJsonStr(list); + String resultStr = chatGPTClient.handleAiChat(promptJson,"CVJX"); + log.info("简历分析优化器:{}",resultStr); + HotakeCvOptimizeDto cvOptimizeDto = new HotakeCvOptimizeDto(); + String resultJson = resultStr.replaceAll("```json","").replaceAll("```",""); + log.info("初筛问题生成:{}",resultStr); + //筛选问题结构化处理-进行初始化问题解析处理 + Map dataMap = JSONUtil.toBean(resultJson,Map.class); + if(dataMap != null){ + //分析总结 + CvAnalysisSummaryDto analysisSummary = new CvAnalysisSummaryDto(); + Map analysisSummaryMap = (Map)dataMap.get("analysis_summary"); + analysisSummary.setOverallScore(analysisSummaryMap.get("overall_score").toString()); + List mainStrengthsList = (List)analysisSummaryMap.get("main_strengths"); + analysisSummary.setMainStrengths(mainStrengthsList); + List criticalIssuesList = (List)analysisSummaryMap.get("critical_issues"); + analysisSummary.setCriticalIssues(criticalIssuesList); + analysisSummary.setImprovementPotential(analysisSummaryMap.get("improvement_potential").toString()); + cvOptimizeDto.setAnalysisSummary(analysisSummary); + + //文本修正(文字、语法等错误) + CvTextCorrectionsDto textCorrections = new CvTextCorrectionsDto(); + Map textCorrectionsMap = (Map)dataMap.get("text_corrections"); + List spellingErrors = new ArrayList<>(); + List spellingErrorsMapList = (List)textCorrectionsMap.get("spelling_errors"); + if(CollectionUtil.isNotEmpty(spellingErrorsMapList)){ + for(Map map : spellingErrorsMapList){ + CvSpellingErrorsDto spellingErrorsDto = new CvSpellingErrorsDto(); + spellingErrorsDto.setOriginal(map.get("original").toString()); + spellingErrorsDto.setCorrected(map.get("corrected").toString()); + spellingErrorsDto.setLocation(map.get("location").toString()); + spellingErrors.add(spellingErrorsDto); + } + textCorrections.setSpellingErrors(spellingErrors); + } + + List grammarErrors = new ArrayList<>(); + List grammarErrorsMapList = (List)textCorrectionsMap.get("grammar_errors"); + if(CollectionUtil.isNotEmpty(grammarErrorsMapList)){ + for(Map map : grammarErrorsMapList){ + CvGrammarErrorsDto grammarErrorsDto = new CvGrammarErrorsDto(); + grammarErrorsDto.setOriginal(map.get("original").toString()); + grammarErrorsDto.setCorrected(map.get("corrected").toString()); + grammarErrorsDto.setLocation(map.get("location").toString()); + grammarErrorsDto.setExplanation(map.get("explanation").toString()); + grammarErrors.add(grammarErrorsDto); + } + textCorrections.setGrammarErrors(grammarErrors); + } + + List formattingIssues = new ArrayList<>(); + List formattingIssuesMapList = (List)textCorrectionsMap.get("formatting_issues"); + if(CollectionUtil.isNotEmpty(formattingIssuesMapList)){ + for(Map map : formattingIssuesMapList){ + CvFormattingIssuesDto formattingIssuesDto = new CvFormattingIssuesDto(); + formattingIssuesDto.setIssue(map.get("issue").toString()); + formattingIssuesDto.setSuggestion(map.get("suggestion").toString()); + List locationList = (List)textCorrectionsMap.get("locations"); + formattingIssuesDto.setLocations(locationList); + formattingIssues.add(formattingIssuesDto); + } + textCorrections.setFormattingIssues(formattingIssues); + } + cvOptimizeDto.setTextCorrections(textCorrections); + + //逻辑修正 + CvLogicCorrectionsDto logicCorrections = new CvLogicCorrectionsDto(); + Map logicCorrectionsMap = (Map)dataMap.get("logic_corrections"); + + List timelineConflicts = new ArrayList<>(); + List timelineConflictsMapList = (List)textCorrectionsMap.get("timeline_conflicts"); + if(CollectionUtil.isNotEmpty(timelineConflictsMapList)){ + for(Map map : timelineConflictsMapList){ + CvTimelineConflictsDto timelineConflictsDto = new CvTimelineConflictsDto(); + timelineConflictsDto.setConflict(map.get("conflict").toString()); + timelineConflictsDto.setDetails(map.get("details").toString()); + timelineConflictsDto.setSuggestion(map.get("suggestion").toString()); + timelineConflicts.add(timelineConflictsDto); + } + logicCorrections.setTimelineConflicts(timelineConflicts); + } + + List careerProgressionDtos = new ArrayList<>(); + List careerProgressionDtosMapList = (List)textCorrectionsMap.get("career_progression"); + if(CollectionUtil.isNotEmpty(careerProgressionDtosMapList)){ + for(Map map : careerProgressionDtosMapList){ + CvCareerProgressionDto careerProgressionDto = new CvCareerProgressionDto(); + careerProgressionDto.setIssue(map.get("issue").toString()); + careerProgressionDto.setDetails(map.get("details").toString()); + careerProgressionDto.setSuggestion(map.get("suggestion").toString()); + careerProgressionDtos.add(careerProgressionDto); + } + logicCorrections.setCareerProgressionDtos(careerProgressionDtos); + } + + List skillExperienceMismatchDtos = new ArrayList<>(); + List skillExperienceMismatchDtosMapList = (List)textCorrectionsMap.get("formatting_issues"); + if(CollectionUtil.isNotEmpty(skillExperienceMismatchDtosMapList)){ + for(Map map : skillExperienceMismatchDtosMapList){ + CvSkillExperienceMismatchDto skillExperienceMismatchDto = new CvSkillExperienceMismatchDto(); + skillExperienceMismatchDto.setIssue(map.get("issue").toString()); + skillExperienceMismatchDto.setSuggestion(map.get("suggestion").toString()); + skillExperienceMismatchDto.setSkill(map.get("suggestion").toString()); + skillExperienceMismatchDtos.add(skillExperienceMismatchDto); + } + logicCorrections.setSkillExperienceMismatchDtos(skillExperienceMismatchDtos); + } + cvOptimizeDto.setLogicCorrections(logicCorrections); + + //优化建议 + CvOptimizationSuggestionsDto optimizationSuggestions = new CvOptimizationSuggestionsDto(); + Map optimizationSuggestionsMap = (Map)dataMap.get("optimization_suggestions"); + CvPersonalSummaryDto personalSummary = new CvPersonalSummaryDto(); + Map personalSummaryMap = (Map)optimizationSuggestionsMap.get("personal_summary"); + if(personalSummaryMap != null){ + List currentIssues = (List)personalSummaryMap.get("current_issues"); + personalSummary.setCurrentIssues(currentIssues); + personalSummary.setOptimizedVersion(personalSummaryMap.get("optimized_version").toString()); + List keyImprovements = (List)personalSummaryMap.get("key_improvements"); + personalSummary.setKeyImprovements(keyImprovements); + } + optimizationSuggestions.setPersonalSummary(personalSummary); + + + List workExperienceDtoList = new ArrayList<>(); + List workExperienceMapList = (List)optimizationSuggestionsMap.get("work_experience"); + if(CollectionUtil.isNotEmpty(workExperienceMapList)){ + for(Map map : workExperienceMapList){ + CvWorkExperienceDto workExperienceDto = new CvWorkExperienceDto(); + workExperienceDto.setPosition(map.get("position").toString()); + workExperienceDto.setOptimizedDescription(map.get("optimized_description").toString()); + workExperienceDto.setCurrentDescription(map.get("current_description").toString()); + List improvements = (List)personalSummaryMap.get("improvements"); + workExperienceDto.setImprovements(improvements); + workExperienceDtoList.add(workExperienceDto); + } + optimizationSuggestions.setWorkExperienceDtoList(workExperienceDtoList); + } + + + CvSkillsSectionDto skillsSection = new CvSkillsSectionDto(); + Map skillsSectionMap = (Map)optimizationSuggestionsMap.get("skills_section"); + if(skillsSectionMap != null){ + List currentIssues = (List)skillsSectionMap.get("current_issues"); + skillsSection.setCurrentIssues(currentIssues); + + CvSuggestedStructureDto suggestedStructureDto = new CvSuggestedStructureDto(); + Map suggestedStructureDtoMap = (Map)skillsSectionMap.get("suggested_structure"); + List coreSkills = (List)suggestedStructureDtoMap.get("core_skills"); + suggestedStructureDto.setCoreSkills(coreSkills); + List technicalSkills = (List)suggestedStructureDtoMap.get("technical_skills"); + suggestedStructureDto.setTechnicalSkills(technicalSkills); + List certifications = (List)suggestedStructureDtoMap.get("certifications"); + suggestedStructureDto.setCertifications(certifications); + skillsSection.setSuggestedStructureDto(suggestedStructureDto); + } + optimizationSuggestions.setSkillsSection(skillsSection); + + + CvKeywordOptimizationDto keywordOptimization = new CvKeywordOptimizationDto(); + Map keywordOptimizationMap = (Map)optimizationSuggestionsMap.get("keyword_optimization"); + if(keywordOptimizationMap != null){ + List atsKeywords = (List)keywordOptimizationMap.get("ats_keywords"); + keywordOptimization.setAtsKeywords(atsKeywords); + + List missingKeywords = (List)keywordOptimizationMap.get("missing_keywords"); + keywordOptimization.setMissingKeywords(missingKeywords); + + List industryTerms = (List)keywordOptimizationMap.get("industry_terms"); + keywordOptimization.setIndustryTerms(industryTerms); + } + optimizationSuggestions.setKeywordOptimization(keywordOptimization); + + cvOptimizeDto.setOptimizationSuggestions(optimizationSuggestions); + + //行动计划 + CvActionPlanDto actionPlan = new CvActionPlanDto(); + Map actionPlanMap = (Map)dataMap.get("action_plan"); + if(actionPlanMap != null){ + List immediateFixes = (List)actionPlanMap.get("immediate_fixes"); + actionPlan.setImmediateFixes(immediateFixes); + + List contentImprovements = (List)actionPlanMap.get("content_improvements"); + actionPlan.setContentImprovements(contentImprovements); + + List strategicEnhancements = (List)actionPlanMap.get("strategic_enhancements"); + actionPlan.setStrategicEnhancements(strategicEnhancements); + } + cvOptimizeDto.setActionPlan(actionPlan); + + //预期改进效果 + CvEstimatedImprovementDto estimatedImprovement = new CvEstimatedImprovementDto(); + Map estimatedImprovementMap = (Map)dataMap.get("estimated_improvement"); + if(estimatedImprovementMap != null){ + estimatedImprovement.setCurrentAtsScore(estimatedImprovementMap.get("current_ats_score").toString()); + estimatedImprovement.setInterviewProbability(estimatedImprovementMap.get("interview_probability").toString()); + estimatedImprovement.setPotentialAtsScore(estimatedImprovementMap.get("potential_ats_score").toString()); + estimatedImprovement.setRecruiterAppeal(estimatedImprovementMap.get("recruiter_appeal").toString()); + } + cvOptimizeDto.setEstimatedImprovement(estimatedImprovement); + } + + return cvOptimizeDto; + } + + /** + * 初步筛选问题淘汰评分 + * @param cvConnect + * @return + */ + @Override + public HotakeInitialQuestionEliminationScoreDto getInitialQuestionEliminationScore(HotakeInitialQuestionEliminationScoreVo questionEliminationScoreVo) { + HotakeInitialQuestionEliminationScoreDto dto = new HotakeInitialQuestionEliminationScoreDto(); + //查询岗位对应的初步筛选问题数据集合 + HotakeInitialScreeningQuestionsInfo queryQuestionsInfo = new HotakeInitialScreeningQuestionsInfo(); + queryQuestionsInfo.setRoleId(questionEliminationScoreVo.getRoleId()); + List screeningQuestionsInfoList = hotakeInitialScreeningQuestionsInfoMapper.selectHotakeInitialScreeningQuestionsInfoList(queryQuestionsInfo); + + //提示词处理 + String prompt = initializationQuestionEliminationScorePrompt(questionEliminationScoreVo.getRoleName()); + List> list = new LinkedList(); + Map mapEntity = new HashMap<>(); + mapEntity.put("role", "system"); + mapEntity.put("content",prompt); + list.add(mapEntity); + + if(CollectionUtil.isNotEmpty(screeningQuestionsInfoList)){ + for(HotakeInitialScreeningQuestionsInfo questionsInfo : screeningQuestionsInfoList){ + //根据问题获取答案数据 + String answer = ""; + if(CollectionUtil.isNotEmpty(questionEliminationScoreVo.getInitScreQuestionsReplyRecordInfoList())){ + List initScreQuestionsReplyRecordInfoList = questionEliminationScoreVo. + getInitScreQuestionsReplyRecordInfoList().stream().filter(e->e.getQuestionId().longValue() == questionsInfo.getId().longValue()).toList(); + if(CollectionUtil.isNotEmpty(initScreQuestionsReplyRecordInfoList)){ + answer = initScreQuestionsReplyRecordInfoList.get(0).getAnswerConnect(); + } + } + Map mapUserEntity = new HashMap<>(); + mapUserEntity.put("role", "user"); + mapUserEntity.put("content", "question:"+questionsInfo.getQuestionTitle()+",answer:"+answer); + list.add(mapUserEntity); + } + } + String promptJson = JSONUtil.toJsonStr(list); + String resultStr = chatGPTClient.handleAiChat(promptJson,"CBQPF"); + log.info("初步筛选问题评分数据:{}",resultStr); + //初步筛选问题评分数据 + dto = JSONUtil.toBean(resultStr,HotakeInitialQuestionEliminationScoreDto.class); + return dto; + } + + + /** + * 初始化职位描述生成器提示词 + * @param jobTitle Specific position 岗位 + * @param industry Industry sector 行业领域 + * @param coreRequirements Key skills or experience requirements 所需技能或经验 + * @return + */ + private String initializationJobDescriptionPrompt(String jobTitle,String industry,String coreRequirements){ + String prompt = "You are a senior HR expert and recruitment copywriter specializing in optimizing and generating attractive job descriptions.\n" + + "\n" + + "Core Task:\n" + + "Generate standardized, professional, and candidate-attractive job description copy based on user-provided \"job title, industry, and core requirements.\"\n" + + "\n" + + "Input Format:\n" + + "- Job Title: ["+jobTitle+"]\n" + + "- Industry: ["+industry+"]\n" + + "- Core Requirements: ["+coreRequirements+"]\n" + + "\n" + + "Output Structure:\n" + + "1. Job Description\n" + + "2. Key Responsibilities\n" + + "3. Requirements\n" + + "\n" + + "Writing Principles:\n" + + "1. Professional yet approachable language, avoiding overly formal or rigid tone\n" + + "2. Highlight career development prospects and value\n" + + "3. Specific and clear requirements, avoiding vague statements\n" + + "4. Reflect company culture and team atmosphere\n" + + "5. Use industry-standard terminology to ensure professionalism\n" + + "\n" + + "Job Description Guidelines:\n" + + "- Concisely summarize the core value and significance of the position\n" + + "- Highlight the position's importance within the company/team\n" + + "- Emphasize career development opportunities\n" + + "- Keep length between 100-150 words\n" + + "\n" + + "Key Responsibilities Guidelines:\n" + + "- List 5-8 specific responsibilities\n" + + "- Arrange by importance\n" + + "- Start with action verbs, be specific\n" + + "- Reflect work challenges and growth opportunities\n" + + "\n" + + "Requirements Guidelines:\n" + + "- Separate into essential requirements and preferred qualifications\n" + + "- Include four dimensions: education, experience, skills, and qualities\n" + + "- Reasonable requirements, avoid excessive barriers\n" + + "- Reflect position-specific needs\n" + + "\n" + + "Target Industry Adaptation:\n" + + "\n" + + "### Construction Industry\n" + + "- Core Keywords: Safety first, quality control, project management, teamwork\n" + + "- Key Requirements: Safety awareness, field experience, technical qualifications, stress resistance\n" + + "- Development Path: Technical specialization, project management, safety management, quality control\n" + + "\n" + + "### Logistics Industry\n" + + "- Core Keywords: Efficiency optimization, cost control, supply chain management, customer service\n" + + "- Key Requirements: Time management, communication coordination, problem solving, strong responsibility\n" + + "- Development Path: Operations optimization, management advancement, professional certification, cross-departmental development\n" + + "\n" + + "### Manufacturing Industry\n" + + "- Core Keywords: Production efficiency, quality standards, safe operations, continuous improvement\n" + + "- Key Requirements: Technical skills, safety awareness, teamwork, learning ability\n" + + "- Development Path: Skill enhancement, team leader, supervisor, professional technical route\n" + + "\n" + + "### Hospitality Industry\n" + + "- Core Keywords: Customer service, teamwork, flexibility, professional image\n" + + "- Key Requirements: Service mindset, communication skills, stress resistance, language abilities\n" + + "- Development Path: Service specialization, management training, department supervisor, hotel management\n" + + "\n" + + "### Mining Industry\n" + + "- Core Keywords: Safe operations, environmental protection, technical standards, teamwork\n" + + "- Key Requirements: Safety awareness, physical requirements, technical qualifications, emergency response\n" + + "- Development Path: Technical certification, safety management, equipment expertise, field management\n" + + "\n" + + "Language Style:\n" + + "- Practical and down-to-earth, close to frontline work\n" + + "- Emphasize the importance of safety and quality\n" + + "- Highlight career development and skill enhancement opportunities\n" + + "- Emphasize teamwork and responsibility\n" + + "- Avoid overly technical expressions, use clear and understandable language\n" + + "\n" + + "Output Format Requirements:\n" + + "Must return standard JSON format with the following structure:\n" + + "\n" + + "```json\n" + + "{\n" + + " \"job_description\": {\n" + + " \"overview\": \"Concise description of position value and significance\",\n" + + " \"development_prospects\": \"Career development prospects description\"\n" + + " },\n" + + " \"key_responsibilities\": [\n" + + " {\n" + + " \"id\": 1,\n" + + " \"responsibility\": \"Specific responsibility description\",\n" + + " \"priority\": \"high|medium|low\"\n" + + " }\n" + + " ],\n" + + " \"requirements\": {\n" + + " \"essential\": [\n" + + " {\n" + + " \"category\": \"education|experience|skills|qualities\",\n" + + " \"requirement\": \"Specific requirement description\",\n" + + " \"details\": \"Detailed explanation\"\n" + + " }\n" + + " ],\n" + + " \"preferred\": [\n" + + " {\n" + + " \"category\": \"education|experience|skills|qualities\", \n" + + " \"requirement\": \"Preferred condition description\",\n" + + " \"details\": \"Detailed explanation\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"company_culture\": \"Company culture and team atmosphere description\",\n" + + " \"industry_focus\": \"Industry characteristics and focus\",\n" + + " \"total_responsibilities\": 6,\n" + + " \"total_essential_requirements\": 4,\n" + + " \"total_preferred_requirements\": 3\n" + + "}\n" + + "```\n" + + "\n" + + "Important Notes:\n" + + "- Ensure content complies with labor laws\n" + + "- Avoid discriminatory language\n" + + "- Maintain content timeliness and accuracy\n" + + "- Adjust requirement difficulty based on different levels"; + + + return prompt; + } + + /** + * 初始化初筛问题生成提示词 + * @param jobTitle 岗位 + * @param jobRequirements 职位要求 + * @param screeningFocus 筛选重点 + * @return + */ + private String initializationInitialScreeningQuestionsPrompt(String jobTitle,String jobRequirements, + String screeningFocus){ + String prompt = "You are an experienced recruitment expert specializing in designing effective screening questions to quickly identify suitable candidates.\n" + + "\n" + + "Core Task:\n" + + "Generate targeted and easily assessable screening questions based on job requirements and specified question types to help HR quickly filter candidates.\n" + + "\n" + + "Input Information:\n" + + "- Job Title: ["+jobTitle+"]\n" + + "- Job Requirements: ["+jobRequirements+"]\n" + + "- Screening Focus: ["+screeningFocus+"]\n" + + "- Question Type: [Specified question type to generate]\n" + + "\n" + + "Supported Question Types:\n" + + "\n" + + "### 1. Single Choice (Radio) - Single Selection\n" + + "- Use Cases: Years of experience, education level, work status, etc.\n" + + "- Features: Only one option can be selected, convenient for quick screening\n" + + "- Examples: Work experience years, highest education, current work status\n" + + "\n" + + "### 2. Multiple Choices (Checkbox) - Multiple Selection\n" + + "- Use Cases: Skills mastery, tool usage, certifications, etc.\n" + + "- Features: Multiple options can be selected, comprehensive understanding of candidate abilities\n" + + "- Examples: Programming languages mastered, tools used, certifications held\n" + + "\n" + + "### 3. Rating Scale (1-5) - Rating Questions\n" + + "- Use Cases: Skill proficiency, experience richness, self-assessment, etc.\n" + + "- Features: 1-5 point scale, convenient for quantitative comparison\n" + + "- Examples: Skill proficiency level, project experience richness, communication ability self-assessment\n" + + "\n" + + "### 4. Short Text Answer - Open-ended Questions\n" + + "- Use Cases: Project experience description, career planning, reasons for leaving, etc.\n" + + "- Features: Requires text description, in-depth understanding of candidate situation\n" + + "- Examples: Project experience description, career development planning, work motivation\n" + + "\n" + + "Question Design Principles:\n" + + "1. Generate questions in the specified format according to the designated question type\n" + + "2. Questions should be specific and clear, avoiding vague statements\n" + + "3. Easy to quantify and compare for assessment\n" + + "4. Quickly identify candidates who don't meet basic requirements\n" + + "5. Cover key dimensions: skills, experience, attitude, etc.\n" + + "6. Limit to 5-8 questions to avoid excessive length\n" + + "\n" + + "Question Type Selection Guidelines:\n" + + "- Basic qualification screening: Prioritize Single Choice\n" + + "- Skills and abilities assessment: Use Multiple Choices or Rating Scale\n" + + "- In-depth experience understanding: Use Short Text Answer\n" + + "- Degree assessment: Use Rating Scale\n" + + "\n" + + "Industry-Specific Questions:\n" + + "\n" + + "### Technology Industry\n" + + "- Data sensitivity, user thinking, rapid learning ability\n" + + "- Attention to and learning capability for new technologies\n" + + "\n" + + "### Sales Positions\n" + + "- Sales performance, client maintenance, stress resistance\n" + + "- Communication skills and negotiation experience\n" + + "\n" + + "### Technical Positions\n" + + "- Programming languages, project experience, technical depth\n" + + "- Ability and methods for learning new technologies\n" + + "\n" + + "### Operations Positions\n" + + "- Data analysis capability, event planning experience\n" + + "- Understanding of user growth and retention\n" + + "\n" + + "Output Format Requirements:\n" + + "Must return standard JSON format with the following structure:\n" + + "\n" + + "```json\n" + + "{\n" + + " \"questions\": [\n" + + " {\n" + + " \"id\": 1,\n" + + " \"type\": \"single_choice|multiple_choices|rating_scale|short_text\",\n" + + " \"question\": \"Question content\",\n" + + " \"options\": [\"Option 1\", \"Option 2\", \"Option 3\"], // Only for single_choice and multiple_choices\n" + + " \"scale\": {\n" + + " \"min\": 1,\n" + + " \"max\": 5,\n" + + " \"labels\": {\n" + + " \"1\": \"Not familiar at all\",\n" + + " \"2\": \"Slightly familiar\", \n" + + " \"3\": \"Moderately familiar\",\n" + + " \"4\": \"Quite familiar\",\n" + + " \"5\": \"Very familiar\"\n" + + " }\n" + + " }, // Only for rating_scale\n" + + " \"placeholder\": \"Please briefly describe...\", // Only for short_text\n" + + " \"required\": true,\n" + + " \"category\": \"basic_qualification|skills_assessment|experience_verification|motivation_attitude|practical_conditions\",\n" + + " \"scoring_criteria\": \"Scoring criteria description\"\n" + + " }\n" + + " ],\n" + + " \"screening_guidelines\": {\n" + + " \"must_meet_conditions\": [\"Must-meet condition 1\", \"Must-meet condition 2\"],\n" + + " \"bonus_points\": [\"Bonus point 1\", \"Bonus point 2\"],\n" + + " \"red_flags\": [\"Red flag 1\", \"Red flag 2\"]\n" + + " },\n" + + " \"total_questions\": 5\n" + + "}\n" + + "```\n" + + "\n" + + "Important Notes:\n" + + "1. Questions must be legal and compliant, avoiding personal privacy\n" + + "2. Avoid discriminatory questions (age, gender, marital status, etc.)\n" + + "3. Questions should be directly related to the position\n" + + "4. Maintain objectivity and fairness in questions\n" + + "5. Consider candidate response time, avoid overly complex questions\n" + + "\n" + + "Quality Checklist:\n" + + "□ Are questions directly related to job requirements?\n" + + "□ Can they effectively distinguish suitable from unsuitable candidates?\n" + + "□ Are question statements clear and understandable?\n" + + "□ Have discriminatory contents been avoided?\n" + + "□ Are assessment criteria clear?"; + + + return prompt; + } + + /** + * 初始化简历岗位匹配度评分提示词 + * + * @param jobTitle 岗位 + * @param jobDescription 岗位描述 + * @param keyResponsibilities 主要职责 + * @param jobRequirements 任职要求 + * @param personalInformation 个人信息 + * @param workHistory 工作经历 + * @param projectExperience 项目经验 + * @param skillsList 技能清单 + * @param educationalBackground 教育背景 + * @param otherRelevantInformation 其他相关信息 + * @return + */ + private String initializationResumeJobMatchingScorePrompt(String jobTitle,String jobDescription, + String keyResponsibilities,String jobRequirements, + String personalInformation,String workHistory, + String projectExperience,String skillsList, + String educationalBackground,String otherRelevantInformation){ + String prompt = "You are a professional resume analysis expert and recruitment consultant, specializing in evaluating the match between candidate resumes and specific job positions.\n" + + "\n" + + "Core Task:\n" + + "Comprehensively analyze candidate resumes and target job requirements to provide objective and accurate job fit scoring and detailed analysis reports.\n" + + "\n" + + "Input Information:\n" + + "1. Job Information:\n" + + " - Job Title:["+jobTitle+"]\n" + + " - Job Description:["+jobDescription+"]\n" + + " - Key Responsibilities:["+keyResponsibilities+"]\n" + + " - Requirements (essential and preferred qualifications):["+jobRequirements+"]\n" + + "\n" + + "2. Candidate Resume:\n" + + " - Personal information (work experience, educational background, etc.):["+personalInformation+"]\n" + + " - Work History:["+workHistory+"]\n" + + " - Project Experience:["+projectExperience+"]\n" + + " - Skills List:["+skillsList+"]\n" + + " - Educational Background:["+educationalBackground+"]\n" + + " - Other relevant information:["+otherRelevantInformation+"]\n" + + "\n" + + "Scoring Dimensions (Total 100 points):\n" + + "\n" + + "### 1. Work Experience Match (30 points)\n" + + "- Relevant industry experience: 10 points\n" + + "- Similar position experience: 15 points\n" + + "- Work years alignment: 5 points\n" + + "\n" + + "Scoring Standards:\n" + + "- Perfect match: Full points\n" + + "- Highly relevant: 80-90%\n" + + "- Partially relevant: 60-79%\n" + + "- Slightly relevant: 40-59%\n" + + "- Not relevant: 0-39%\n" + + "\n" + + "### 2. Skills and Abilities Match (25 points)\n" + + "- Professional skills: 15 points\n" + + "- Soft skills: 10 points\n" + + "\n" + + "Scoring Focus:\n" + + "- Mastery level of essential skills\n" + + "- Coverage of preferred skills\n" + + "- Skill depth and breadth\n" + + "- Demonstration of learning ability\n" + + "\n" + + "### 3. Educational Background Match (15 points)\n" + + "- Education level: 8 points\n" + + "- Major relevance: 7 points\n" + + "\n" + + "Considerations:\n" + + "- Whether education level meets requirements\n" + + "- Degree of major background relevance\n" + + "- Continuous learning and professional development\n" + + "\n" + + "### 4. Project Experience Match (20 points)\n" + + "- Project scale and complexity: 10 points\n" + + "- Project outcomes and impact: 10 points\n" + + "\n" + + "Assessment Points:\n" + + "- Relevance of projects to target position\n" + + "- Role and responsibilities in projects\n" + + "- Quantified project achievements\n" + + "- Demonstration of problem-solving abilities\n" + + "\n" + + "### 5. Overall Quality Assessment (10 points)\n" + + "- Career development trajectory: 5 points\n" + + "- Stability and growth potential: 5 points\n" + + "\n" + + "Considerations:\n" + + "- Logic and coherence of career development\n" + + "- Work stability (job-hopping frequency and reasons)\n" + + "- Growth potential and learning ability\n" + + "- Clarity of career planning\n" + + "\n" + + "Output Format Requirements:\n" + + "Must return standard JSON format with the following structure:\n" + + "\n" + + "```json\n" + + "{\n" + + " \"overall_score\": {\n" + + " \"total_score\": 85,\n" + + " \"max_score\": 100,\n" + + " \"match_level\": \"excellent|good|average|poor\",\n" + + " \"recommendation\": \"strongly_recommend|recommend|consider_carefully|not_recommend\"\n" + + " },\n" + + " \"detailed_scores\": {\n" + + " \"work_experience\": {\n" + + " \"total\": 25,\n" + + " \"max\": 30,\n" + + " \"breakdown\": {\n" + + " \"industry_experience\": {\"score\": 8, \"max\": 10, \"analysis\": \"Analysis explanation\"},\n" + + " \"similar_position\": {\"score\": 12, \"max\": 15, \"analysis\": \"Analysis explanation\"},\n" + + " \"work_years\": {\"score\": 5, \"max\": 5, \"analysis\": \"Analysis explanation\"}\n" + + " }\n" + + " },\n" + + " \"skills_abilities\": {\n" + + " \"total\": 20,\n" + + " \"max\": 25,\n" + + " \"breakdown\": {\n" + + " \"professional_skills\": {\"score\": 12, \"max\": 15, \"matching_skills\": [\"Skill 1\", \"Skill 2\"], \"missing_skills\": [\"Missing skill 1\"]},\n" + + " \"soft_skills\": {\"score\": 8, \"max\": 10, \"analysis\": \"Analysis explanation\"}\n" + + " }\n" + + " },\n" + + " \"education\": {\n" + + " \"total\": 12,\n" + + " \"max\": 15,\n" + + " \"breakdown\": {\n" + + " \"education_level\": {\"score\": 6, \"max\": 8, \"analysis\": \"Analysis explanation\"},\n" + + " \"major_relevance\": {\"score\": 6, \"max\": 7, \"analysis\": \"Analysis explanation\"}\n" + + " }\n" + + " },\n" + + " \"project_experience\": {\n" + + " \"total\": 18,\n" + + " \"max\": 20,\n" + + " \"relevant_projects\": [\"Project 1\", \"Project 2\"],\n" + + " \"achievement_highlights\": [\"Achievement 1\", \"Achievement 2\"],\n" + + " \"analysis\": \"Project experience analysis\"\n" + + " },\n" + + " \"overall_quality\": {\n" + + " \"total\": 8,\n" + + " \"max\": 10,\n" + + " \"breakdown\": {\n" + + " \"career_trajectory\": {\"score\": 4, \"max\": 5, \"analysis\": \"Analysis explanation\"},\n" + + " \"stability_growth\": {\"score\": 4, \"max\": 5, \"analysis\": \"Analysis explanation\"}\n" + + " }\n" + + " }\n" + + " },\n" + + " \"match_highlights\": [\n" + + " \"Outstanding matching advantage 1\",\n" + + " \"Outstanding matching advantage 2\",\n" + + " \"Outstanding matching advantage 3\"\n" + + " ],\n" + + " \"risk_points\": [\n" + + " \"Issue requiring attention 1\",\n" + + " \"Issue requiring attention 2\"\n" + + " ],\n" + + " \"interview_recommendations\": {\n" + + " \"key_assessment_areas\": [\"Key assessment area 1\", \"Key assessment area 2\"],\n" + + " \"critical_questions\": [\"Suggested interview question 1\", \"Suggested interview question 2\"],\n" + + " \"skill_verification\": [\"Skill to verify 1\", \"Skill to verify 2\"]\n" + + " },\n" + + " \"hiring_recommendation\": {\n" + + " \"level\": \"strongly_recommend|recommend|consider_carefully|not_recommend\",\n" + + " \"reasoning\": \"Brief explanation of recommendation\"\n" + + " }\n" + + "}\n" + + "```\n" + + "\n" + + "Scoring Level Descriptions:\n" + + "- 90-100 points: Excellent match, strongly recommend\n" + + "- 80-89 points: Good match, recommend for interview\n" + + "- 70-79 points: Average match, consider for interview\n" + + "- 60-69 points: Low match, consider carefully\n" + + "- Below 60 points: Poor match, not recommended\n" + + "\n" + + "Important Notes:\n" + + "1. Maintain objectivity and fairness, base assessment on facts\n" + + "2. Avoid personal bias and discrimination\n" + + "3. Consider candidate's growth potential\n" + + "4. Combine company culture and team needs\n" + + "5. Provide constructive analysis and recommendations\n" + + "\n" + + "Quality Check:\n" + + "□ Is the scoring well-supported by evidence?\n" + + "□ Is the analysis objective and comprehensive?\n" + + "□ Are all key dimensions considered?\n" + + "□ Are recommendations actionable?\n" + + "□ Have discriminatory evaluations been avoided?"; + + + return prompt; + } + + /** + * 初始化简历优化分析器提示词 + * @return + */ + private String initializationResumeAnalysisOptimizerPrompt(){ + String prompt = "You are a professional resume analysis and optimization expert, specializing in providing resume improvement recommendations for traditional industries including construction, logistics, manufacturing, hospitality, and mining.\n" + + "\n" + + "## Core Mission\n" + + "Analyze uploaded resumes, identify issues, and provide optimization recommendations to help candidates improve resume quality and job search success rates.\n" + + "\n" + + "## Analysis Dimensions\n" + + "\n" + + "### 1. Text Correction Analysis\n" + + "Check for the following issues:\n" + + "- **Spelling Errors**: Identify word spelling mistakes\n" + + "- **Grammar Errors**: Sentence structure, tense, and grammatical issues\n" + + "- **Punctuation**: Improper or missing punctuation usage\n" + + "- **Format Consistency**: Date formats, capitalization, abbreviation uniformity\n" + + "- **Professional Terminology**: Accuracy of industry-specific terms\n" + + "\n" + + "### 2. Logic Correction Analysis\n" + + "Check for the following issues:\n" + + "- **Timeline Conflicts**: Overlapping or illogical dates in work/education history\n" + + "- **Career Progression Logic**: Whether promotion paths are reasonable\n" + + "- **Skill Matching**: Whether claimed skills match work experience\n" + + "- **Experience Consistency**: Whether descriptions across sections are consistent\n" + + "- **Gap Explanations**: Whether employment gaps need clarification\n" + + "\n" + + "### 3. Content Optimization Recommendations\n" + + "Provide the following optimization suggestions:\n" + + "- **Personal Summary Optimization**: Highlight core strengths and value proposition\n" + + "- **Work Experience Optimization**: Use quantified data and specific achievements\n" + + "- **Skills Display Optimization**: Organize by importance and relevance\n" + + "- **Keyword Optimization**: Add industry-relevant keywords\n" + + "- **Structure Optimization**: Improve resume layout and information hierarchy\n" + + "\n" + + "## Traditional Industry Focus\n" + + "\n" + + "### Construction Industry Priorities\n" + + "- Safety qualifications and certifications\n" + + "- Project scale and complexity\n" + + "- Site management experience\n" + + "- Quality control capabilities\n" + + "\n" + + "### Logistics Industry Priorities\n" + + "- Transportation efficiency optimization\n" + + "- Inventory management experience\n" + + "- Customer service capabilities\n" + + "- Cost control achievements\n" + + "\n" + + "### Manufacturing Industry Priorities\n" + + "- Production efficiency improvements\n" + + "- Quality management systems\n" + + "- Equipment operation skills\n" + + "- Safety operation records\n" + + "\n" + + "### Hospitality Industry Priorities\n" + + "- Customer service experience\n" + + "- Multilingual capabilities\n" + + "- Team collaboration skills\n" + + "- Sales performance\n" + + "\n" + + "### Mining Industry Priorities\n" + + "- Safety operation qualifications\n" + + "- Equipment operation experience\n" + + "- Environmental adaptability\n" + + "- Technical compliance adherence\n" + + "\n" + + "## Output Format\n" + + "\n" + + "Please strictly follow this JSON format for analysis results:\n" + + "\n" + + "```json\n" + + "{\n" + + " \"analysis_summary\": {\n" + + " \"overall_score\": 85,\n" + + " \"main_strengths\": [\"Specific strength 1\", \"Specific strength 2\"],\n" + + " \"critical_issues\": [\"Critical issue 1\", \"Critical issue 2\"],\n" + + " \"improvement_potential\": \"high|medium|low\"\n" + + " },\n" + + " \"text_corrections\": {\n" + + " \"spelling_errors\": [\n" + + " {\n" + + " \"original\": \"Incorrect text\",\n" + + " \"corrected\": \"Correct text\",\n" + + " \"location\": \"Personal summary line 2\"\n" + + " }\n" + + " ],\n" + + " \"grammar_errors\": [\n" + + " {\n" + + " \"original\": \"Grammatically incorrect sentence\",\n" + + " \"corrected\": \"Corrected sentence\",\n" + + " \"location\": \"Work experience item 1\",\n" + + " \"explanation\": \"Tense inconsistency\"\n" + + " }\n" + + " ],\n" + + " \"formatting_issues\": [\n" + + " {\n" + + " \"issue\": \"Inconsistent date format\",\n" + + " \"suggestion\": \"Use consistent MM/YYYY format\",\n" + + " \"locations\": [\"Work Experience\", \"Education\"]\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"logic_corrections\": {\n" + + " \"timeline_conflicts\": [\n" + + " {\n" + + " \"conflict\": \"Overlapping work periods\",\n" + + " \"details\": \"2020-2022 at Company A, 2021-2023 at Company B\",\n" + + " \"suggestion\": \"Verify and correct timeline, or explain part-time situation\"\n" + + " }\n" + + " ],\n" + + " \"career_progression\": [\n" + + " {\n" + + " \"issue\": \"Position regression\",\n" + + " \"details\": \"From Manager to Assistant\",\n" + + " \"suggestion\": \"Explain reason for position change or adjust description\"\n" + + " }\n" + + " ],\n" + + " \"skill_experience_mismatch\": [\n" + + " {\n" + + " \"skill\": \"Project Management\",\n" + + " \"issue\": \"Claims 5 years experience but work history shows only 2 years\",\n" + + " \"suggestion\": \"Adjust skill description or add relevant experience\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"optimization_suggestions\": {\n" + + " \"personal_summary\": {\n" + + " \"current_issues\": [\"Too generic\", \"Lacks quantified data\"],\n" + + " \"optimized_version\": \"Experienced construction project manager with 8 years in residential and commercial projects, successfully managing projects worth over $5M, specializing in cost control and quality management, certified PMP with White Card qualification.\",\n" + + " \"key_improvements\": [\"Add specific numbers\", \"Highlight core qualifications\", \"Emphasize industry experience\"]\n" + + " },\n" + + " \"work_experience\": [\n" + + " {\n" + + " \"position\": \"Project Manager - ABC Construction\",\n" + + " \"current_description\": \"Responsible for project management work\",\n" + + " \"optimized_description\": \"• Managed 3 concurrent residential projects worth $2.8M, achieving 100% on-time, on-budget completion rate\\n• Coordinated 15-person team including engineers, contractors, and suppliers\\n• Implemented quality control processes, reducing rework by 25%\",\n" + + " \"improvements\": [\"Quantify achievements\", \"Specific responsibilities\", \"Highlight accomplishments\"]\n" + + " }\n" + + " ],\n" + + " \"skills_section\": {\n" + + " \"current_issues\": [\"Poor skill ordering\", \"Missing industry keywords\"],\n" + + " \"suggested_structure\": {\n" + + " \"core_skills\": [\"Project Management\", \"Quality Control\", \"Cost Management\", \"Team Leadership\"],\n" + + " \"technical_skills\": [\"AutoCAD\", \"MS Project\", \"Building Codes\", \"Safety Management\"],\n" + + " \"certifications\": [\"PMP\", \"White Card\", \"First Aid\", \"WHS Certificate\"]\n" + + " }\n" + + " },\n" + + " \"keyword_optimization\": {\n" + + " \"missing_keywords\": [\"Construction Management\", \"Site Supervision\", \"Safety Compliance\", \"Budget Control\"],\n" + + " \"industry_terms\": [\"Residential Construction\", \"Commercial Projects\", \"Subcontractor Management\", \"Quality Assurance\"],\n" + + " \"ats_keywords\": [\"Project Delivery\", \"Cost Effectiveness\", \"Team Collaboration\", \"Customer Satisfaction\"]\n" + + " }\n" + + " },\n" + + " \"action_plan\": {\n" + + " \"immediate_fixes\": [\n" + + " \"Correct all spelling and grammar errors\",\n" + + " \"Standardize dates and formatting\",\n" + + " \"Resolve timeline conflicts\"\n" + + " ],\n" + + " \"content_improvements\": [\n" + + " \"Rewrite personal summary to highlight core value\",\n" + + " \"Add quantified achievements to each work experience\",\n" + + " \"Reorganize skills section\"\n" + + " ],\n" + + " \"strategic_enhancements\": [\n" + + " \"Add industry-relevant keywords\",\n" + + " \"Highlight safety and compliance experience\",\n" + + " \"Emphasize project management achievements\"\n" + + " ]\n" + + " },\n" + + " \"estimated_improvement\": {\n" + + " \"current_ats_score\": 65,\n" + + " \"potential_ats_score\": 85,\n" + + " \"recruiter_appeal\": \"Significantly improved\",\n" + + " \"interview_probability\": \"+40%\"\n" + + " }\n" + + "}\n" + + "```\n" + + "\n" + + "## Analysis Principles\n" + + "\n" + + "1. **Constructive**: All suggestions should be actionable improvement recommendations\n" + + "2. **Specific**: Provide concrete modification examples, not just general advice\n" + + "3. **Industry-Relevant**: Offer targeted suggestions based on target industry characteristics\n" + + "4. **Balanced**: Point out issues while also acknowledging strengths\n" + + "5. **Practical**: Consider actual needs of ATS systems and recruiters\n" + + "\n" + + "## Important Notes\n" + + "\n" + + "- Maintain professional and encouraging tone\n" + + "- Avoid overly harsh criticism\n" + + "- Provide feasible solutions\n" + + "- Consider candidates of different experience levels\n" + + "- Respect personal privacy, don't request sensitive information"; + + return prompt; + } + + + /** + * 初始化初步筛选问题淘汰评分提示词 + * @return + */ + private String initializationQuestionEliminationScorePrompt(String roleName){ + + String prompt = "你是资深的面试专家和职业顾问,专注于为建筑、物流、制造、酒店、矿业等传统行业的求职者初步筛选面试回答进行打分,分数区间为0到100分。\n" + + "\n" + + "##核心任务\n" + + "根据所提供的问题与答案,结合所申请的岗位,进行最终的打分与评价说明.\n" + + "\n" + + "##输入项参数\n" + + "岗位:[]\n" + + "\n" + + "##返回的结构\n" + + "\n" + + "{ \\\"score\\\": \\\"\\\", \\\"evaluate\\\": \\\"\\\"}。字段不存在则返回 null 或空数组。只返回标准可解析的 JSON结构 ,不要多余的```json等信息,score为分数,evaluate为评价说明(返回英文)"; + + return prompt; + } + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java index eb9b8bf..8119779 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java @@ -14,8 +14,10 @@ import com.vetti.common.utils.readFile.FileContentUtil; import com.vetti.hotake.domain.HotakeCvInfo; import com.vetti.hotake.domain.HotakeProblemBaseInfo; import com.vetti.hotake.domain.dto.HotakeCvInfoDto; +import com.vetti.hotake.domain.dto.HotakeCvOptimizeDto; import com.vetti.hotake.domain.dto.VcDto.*; import com.vetti.hotake.mapper.HotakeCvInfoMapper; +import com.vetti.hotake.service.IHotakeAiCommonToolsService; import com.vetti.hotake.service.IHotakeCvInfoService; import com.vetti.hotake.service.IHotakeProblemBaseInfoService; import io.minio.GetObjectArgs; @@ -60,6 +62,9 @@ public class HotakeCvInfoServiceImpl extends BaseServiceImpl implements IHotakeC @Autowired private IHotakeProblemBaseInfoService hotakeProblemBaseInfoService; + @Autowired + private IHotakeAiCommonToolsService aiCommonToolsService; + /** * 查询简历信息 * @@ -74,7 +79,23 @@ public class HotakeCvInfoServiceImpl extends BaseServiceImpl implements IHotakeC HotakeCvInfoDto cvInfoDto = JSONUtil.toBean(cvInfo.getCvTemplateJson(),HotakeCvInfoDto.class); cvInfo.setCvInfoDto(cvInfoDto); } - + if(StrUtil.isNotEmpty(cvInfo.getCvOptimizeJson())){ + //解析优化简历 + HotakeCvOptimizeDto cvOptimizeDto = JSONUtil.toBean(cvInfo.getCvOptimizeJson(),HotakeCvOptimizeDto.class); + if(cvOptimizeDto != null){ + cvInfo.setCvOptimizeDto(cvOptimizeDto); + if(cvOptimizeDto.getTextCorrections() != null && CollectionUtil.isNotEmpty(cvOptimizeDto.getTextCorrections().getFormattingIssues())){ + cvInfo.setTextCorrectionsNums(cvOptimizeDto.getTextCorrections().getFormattingIssues().size()); + }else{ + cvInfo.setTextCorrectionsNums(0); + } + if(cvOptimizeDto.getLogicCorrections() != null && CollectionUtil.isNotEmpty(cvOptimizeDto.getLogicCorrections().getCareerProgressionDtos())){ + cvInfo.setLogicCorrectionsNum(cvOptimizeDto.getTextCorrections().getFormattingIssues().size()); + }else{ + cvInfo.setLogicCorrectionsNum(0); + } + } + } HotakeProblemBaseInfo query = new HotakeProblemBaseInfo(); query.setCvId(id); List problemBaseInfoList = hotakeProblemBaseInfoService.selectHotakeProblemBaseInfoList(query); @@ -264,25 +285,42 @@ public class HotakeCvInfoServiceImpl extends BaseServiceImpl implements IHotakeC //对简历数据进行处理生成相应的题库数据 HotakeProblemBaseInfo problemBaseInfo = handleHotakeCvInfo(cvInfoDto,hotakeCvInfo.getId()); cvInfo.setProblemBaseInfo(problemBaseInfo); - //生成对应的简历评分 - String resultMsg = handleHotakeCvInfoScore(cvInfoDto); - cvInfo.setCvScore(resultMsg); - cvInfo.setExperience(cvInfoDto.getExperienceYear()); - //分数解析 - String[] strs = resultMsg.split("\n"); - if(strs != null && strs.length > 0){ - String score = strs[0].replaceAll("Score:","").trim(); - String[] scores = score.split("/"); - if(scores != null && scores.length > 0){ - cvInfo.setAiMatchScore(scores[0]); - try{ - cvInfo.setAiMatchScorePercentage(String.valueOf(new BigDecimal(scores[0]). - divide(new BigDecimal(5)).setScale(2,4))); - }catch (Exception e){e.printStackTrace();} + //解析优化简历 + HotakeCvOptimizeDto cvOptimizeDto = aiCommonToolsService.getResumeAnalysisOptimizer(contents); + if(cvOptimizeDto != null){ + cvInfo.setCvOptimizeJson(JSONUtil.toJsonStr(cvOptimizeDto)); + if(cvOptimizeDto.getTextCorrections() != null && CollectionUtil.isNotEmpty(cvOptimizeDto.getTextCorrections().getFormattingIssues())){ + cvInfo.setTextCorrectionsNums(cvOptimizeDto.getTextCorrections().getFormattingIssues().size()); + }else{ + cvInfo.setTextCorrectionsNums(0); } + if(cvOptimizeDto.getLogicCorrections() != null && CollectionUtil.isNotEmpty(cvOptimizeDto.getLogicCorrections().getCareerProgressionDtos())){ + cvInfo.setLogicCorrectionsNum(cvOptimizeDto.getTextCorrections().getFormattingIssues().size()); + }else{ + cvInfo.setLogicCorrectionsNum(0); + } + cvInfo.setCvOptimizeDto(cvOptimizeDto); } +// //生成对应的简历评分 +// String resultMsg = handleHotakeCvInfoScore(cvInfoDto); +// cvInfo.setCvScore(resultMsg); + cvInfo.setExperience(cvInfoDto.getExperienceYear()); + //分数解析 +// String[] strs = resultMsg.split("\n"); +// if(strs != null && strs.length > 0){ +// String score = strs[0].replaceAll("Score:","").trim(); +// String[] scores = score.split("/"); +// if(scores != null && scores.length > 0){ +// cvInfo.setAiMatchScore(scores[0]); +// try{ +// cvInfo.setAiMatchScorePercentage(String.valueOf(new BigDecimal(scores[0]). +// divide(new BigDecimal(5)).setScale(2,4))); +// }catch (Exception e){e.printStackTrace();} +// +// } +// } cvInfo.setCvTemplateJson(JSONUtil.toJsonStr(cvInfoDto)); fill(FillTypeEnum.UPDATE.getCode(), cvInfo); hotakeCvInfoMapper.updateHotakeCvInfo(cvInfo); 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 b3696d7..60de701 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 @@ -22,11 +22,14 @@ import com.vetti.common.utils.SecurityUtils; import com.vetti.common.utils.readFile.FileContentUtil; import com.vetti.hotake.domain.*; import com.vetti.hotake.domain.dto.HotakeCvInfoDto; +import com.vetti.hotake.domain.dto.HotakeInitialQuestionEliminationScoreDto; import com.vetti.hotake.domain.dto.VcDto.*; import com.vetti.hotake.domain.vo.HotakeInitScreQuestionsReplyRecordInfoVo; +import com.vetti.hotake.domain.vo.HotakeInitialQuestionEliminationScoreVo; import com.vetti.hotake.mapper.HotakeCvInfoMapper; import com.vetti.hotake.mapper.HotakeRolesApplyInfoMapper; import com.vetti.hotake.mapper.HotakeRolesInfoMapper; +import com.vetti.hotake.service.IHotakeAiCommonToolsService; import io.minio.GetObjectArgs; import io.minio.MinioClient; import lombok.extern.slf4j.Slf4j; @@ -60,6 +63,9 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi @Autowired private HotakeCvInfoMapper hotakeCvInfoMapper; + @Autowired + private IHotakeAiCommonToolsService aiCommonToolsService; + @Autowired private MinioClient minioClient; @@ -180,62 +186,70 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi HotakeRolesApplyInfo applyInfo = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoById(initScreQuestionsReplyRecordInfoVo.getRoleApplyId()); if (applyInfo != null) { HotakeRolesInfo rolesInf = hotakeRolesInfoMapper.selectHotakeRolesInfoById(initScreQuestionsReplyRecordInfoVo.getRoleId()); + //获取初步筛选问题评分 + HotakeInitialQuestionEliminationScoreVo eliminationScoreVo = new HotakeInitialQuestionEliminationScoreVo(); + eliminationScoreVo.setRoleId(rolesInf.getId()); + eliminationScoreVo.setRoleName(rolesInf.getRoleName()); + eliminationScoreVo.setInitScreQuestionsReplyRecordInfoList(initScreQuestionsReplyRecordInfoVo.getInitScreQuestionsReplyRecordInfoList()); + HotakeInitialQuestionEliminationScoreDto eliminationScoreDto = aiCommonToolsService.getInitialQuestionEliminationScore(eliminationScoreVo); + + //查询候选人的当前最新简历信息 - HotakeCvInfo queryCv = new HotakeCvInfo(); - queryCv.setUserId(SecurityUtils.getUserId()); - queryCv.setCvFileType("cv"); - List cvInfos = hotakeCvInfoMapper.selectHotakeCvInfoList(queryCv); - HotakeCvInfo cvInfo = null; - if(CollectionUtil.isNotEmpty(cvInfos)) { - cvInfo = cvInfos.get(0); - } - //解析简历内容以及获取简历对应的评分数据 - log.info("开始处理简历"); - try { - InputStream inputStream = minioClient.getObject( - GetObjectArgs.builder() - .bucket(MinioBucketNameEnum.CV.getCode()) - .object(applyInfo.getCvFile()) - .build()); - String contents = FileContentUtil.readFileContent(inputStream, applyInfo.getCvFileSuffix()); - log.info("简历信息:{}", contents); - //验证文件内容是否改变,如果未改变不进行模型解析直接返回原有结果 - String md5Hash = MD5.create().digestHex16(contents); - String scoreStr = ""; - if (StrUtil.isNotEmpty(md5Hash) && cvInfo != null && md5Hash.equals(cvInfo.getCvMd5())) { - //直接获取简历表中的简历解析的详细数据 - applyInfo.setCvScore(cvInfo.getCvScore()); - applyInfo.setCvTemplateJson(cvInfo.getCvTemplateJson()); - fill(FillTypeEnum.UPDATE.getCode(), applyInfo); - applyInfo.setCvMd5(md5Hash); - applyInfo.setExperience(cvInfo.getExperience()); - scoreStr = cvInfo.getCvScore(); - }else{ - //生成简历模版数据信息 - HotakeCvInfoDto cvInfoDto = handleAnalysisCvInfo(contents); - //生成对应的简历评分 - String resultMsg = handleHotakeCvInfoScore(cvInfoDto); - applyInfo.setCvScore(resultMsg); - applyInfo.setCvTemplateJson(JSONUtil.toJsonStr(cvInfoDto)); - fill(FillTypeEnum.UPDATE.getCode(), cvInfo); - applyInfo.setCvMd5(md5Hash); - applyInfo.setExperience(cvInfoDto.getExperienceYear()); - scoreStr = resultMsg; - } +// HotakeCvInfo queryCv = new HotakeCvInfo(); +// queryCv.setUserId(SecurityUtils.getUserId()); +// queryCv.setCvFileType("cv"); +// List cvInfos = hotakeCvInfoMapper.selectHotakeCvInfoList(queryCv); +// HotakeCvInfo cvInfo = null; +// if(CollectionUtil.isNotEmpty(cvInfos)) { +// cvInfo = cvInfos.get(0); +// } +// //解析简历内容以及获取简历对应的评分数据 +// log.info("开始处理简历"); +// try { +// InputStream inputStream = minioClient.getObject( +// GetObjectArgs.builder() +// .bucket(MinioBucketNameEnum.CV.getCode()) +// .object(applyInfo.getCvFile()) +// .build()); +// String contents = FileContentUtil.readFileContent(inputStream, applyInfo.getCvFileSuffix()); +// log.info("简历信息:{}", contents); +// //验证文件内容是否改变,如果未改变不进行模型解析直接返回原有结果 +// String md5Hash = MD5.create().digestHex16(contents); +// String scoreStr = ""; +// if (StrUtil.isNotEmpty(md5Hash) && cvInfo != null && md5Hash.equals(cvInfo.getCvMd5())) { +// //直接获取简历表中的简历解析的详细数据 +// applyInfo.setCvScore(cvInfo.getCvScore()); +// applyInfo.setCvTemplateJson(cvInfo.getCvTemplateJson()); +// fill(FillTypeEnum.UPDATE.getCode(), applyInfo); +// applyInfo.setCvMd5(md5Hash); +// applyInfo.setExperience(cvInfo.getExperience()); +// scoreStr = cvInfo.getCvScore(); +// }else{ +// //生成简历模版数据信息 +// HotakeCvInfoDto cvInfoDto = handleAnalysisCvInfo(contents); +// //生成对应的简历评分 +// String resultMsg = handleHotakeCvInfoScore(cvInfoDto); +// applyInfo.setCvScore(resultMsg); +// applyInfo.setCvTemplateJson(JSONUtil.toJsonStr(cvInfoDto)); +// fill(FillTypeEnum.UPDATE.getCode(), cvInfo); +// applyInfo.setCvMd5(md5Hash); +// applyInfo.setExperience(cvInfoDto.getExperienceYear()); +// scoreStr = resultMsg; +// } //更新岗位申请数据记录--根据评分进行计算 //分数解析 - String[] strs = scoreStr.split("\n"); - if(strs != null && strs.length > 0){ - String score = strs[0].replaceAll("Score:","").trim(); - String[] scores = score.split("/"); - if(scores != null && scores.length > 0){ - applyInfo.setAiMatchScore(scores[0]); +// String[] strs = scoreStr.split("\n"); +// if(strs != null && strs.length > 0){ +// String score = strs[0].replaceAll("Score:","").trim(); +// String[] scores = score.split("/"); +// if(scores != null && scores.length > 0){ +// applyInfo.setAiMatchScore(scores[0]); try{ - applyInfo.setAiMatchScorePercentage(new BigDecimal(scores[0]). - divide(new BigDecimal(5)).setScale(2,4)); + applyInfo.setAiMatchScorePercentage(new BigDecimal(eliminationScoreDto.getScore()). + divide(new BigDecimal(100)).setScale(2,4)); }catch (Exception e){e.printStackTrace();} - } - } +// } +// } if(applyInfo.getAiMatchScorePercentage() != null){ if(applyInfo.getAiMatchScorePercentage().compareTo(new BigDecimal(0.85)) >= 0){ applyInfo.setCandidateStatus(CandidateStatusEnum.HOT.getCode()); @@ -252,9 +266,9 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi applyInfo.setRecruiterId(rolesInf.getRecruiterId()); applyInfo.setStage(StageEnum.APPLIED.getCode()); hotakeRolesApplyInfoMapper.updateHotakeRolesApplyInfo(applyInfo); - } catch (Exception e) { - e.printStackTrace(); - } +// } catch (Exception e) { +// e.printStackTrace(); +// } return 0; } return 0; diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitialScreeningQuestionsInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitialScreeningQuestionsInfoServiceImpl.java index e013ef8..ec46229 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitialScreeningQuestionsInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitialScreeningQuestionsInfoServiceImpl.java @@ -8,6 +8,7 @@ import com.vetti.common.enums.FillTypeEnum; import com.vetti.common.utils.SecurityUtils; import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; import com.vetti.hotake.domain.dto.AnswerOptionsDto; +import com.vetti.hotake.domain.vo.HotakeInitialScreeningQuestionsInfoVo; import com.vetti.hotake.mapper.HotakeInitialScreeningQuestionsInfoMapper; import com.vetti.hotake.service.IHotakeInitialScreeningQuestionsInfoService; import org.springframework.beans.factory.annotation.Autowired; @@ -128,12 +129,26 @@ public class HotakeInitialScreeningQuestionsInfoServiceImpl extends BaseServiceI /** * 批量新增初步筛选问题信息 * - * @param hotakeInitialScreeningQuestionsInfoList 初步筛选问题信息列表 + * @param questionsInfoVo 初步筛选问题信息 * @return 结果 */ @Transactional(rollbackFor=Exception.class) @Override - public int batchInsertHotakeInitialScreeningQuestionsInfo(List hotakeInitialScreeningQuestionsInfoList){ - return hotakeInitialScreeningQuestionsInfoMapper.batchInsertHotakeInitialScreeningQuestionsInfo(hotakeInitialScreeningQuestionsInfoList); + public void batchInsertHotakeInitialScreeningQuestionsInfo(HotakeInitialScreeningQuestionsInfoVo questionsInfoVo){ + //先删除之前的初步筛选问题数据 +// hotakeInitialScreeningQuestionsInfoMapper.deleteHotakeInitialScreeningQuestionsInfoByRoleId(questionsInfoVo.getRoleId()); + if(CollectionUtil.isNotEmpty(questionsInfoVo.getQuestionsInfoList())){ + for(HotakeInitialScreeningQuestionsInfo questionsInfo : questionsInfoVo.getQuestionsInfoList()){ + fill(FillTypeEnum.INSERT.getCode(), questionsInfo); + questionsInfo.setRecruiterId(SecurityUtils.getUserId()); + if(CollectionUtil.isNotEmpty(questionsInfo.getAnswerOptionsList())){ + questionsInfo.setAnswerOptions(JSONUtil.toJsonStr(questionsInfo.getAnswerOptionsList())); + }else { + questionsInfo.setAnswerOptions(""); + } + questionsInfo.setRoleId(questionsInfoVo.getRoleId()); + } + hotakeInitialScreeningQuestionsInfoMapper.batchInsertHotakeInitialScreeningQuestionsInfo(questionsInfoVo.getQuestionsInfoList()); + } } } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java index dc2895f..1b0b799 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeMeetingCalendarInfoServiceImpl.java @@ -1,5 +1,7 @@ package com.vetti.hotake.service.impl; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -10,9 +12,11 @@ import com.vetti.common.core.service.BaseServiceImpl; import com.vetti.common.enums.FillTypeEnum; import com.vetti.common.enums.MeetingCalendarStatus; import com.vetti.common.enums.StageEnum; +import com.vetti.common.utils.SecurityUtils; import com.vetti.hotake.domain.HotakeMeetingCalendarDetail; import com.vetti.hotake.domain.HotakeRolesApplyInfo; import com.vetti.hotake.domain.HotakeRolesInfo; +import com.vetti.hotake.domain.dto.HotakeMeetingCalendarDataDto; import com.vetti.hotake.domain.vo.HotakeMeetingCalendarInfoVo; import com.vetti.hotake.domain.vo.HotakeMeetingCalendarVo; import com.vetti.hotake.mapper.HotakeMeetingCalendarDetailMapper; @@ -160,6 +164,69 @@ public class HotakeMeetingCalendarInfoServiceImpl extends BaseServiceImpl implem return calendarInfos; } + /** + * 查询候选者相关的会议记录数据 + * @param hotakeMeetingCalendarInfo 会议日历记录主 + * @return + */ + @Override + public List selectHotakeMeetingCalendarInfoCandidateList(HotakeMeetingCalendarInfo hotakeMeetingCalendarInfo) { + //根据候选者查询会议明细数据 + HotakeMeetingCalendarDetail queryCalendarDetail = new HotakeMeetingCalendarDetail(); + queryCalendarDetail.setCandidateId(SecurityUtils.getUserId()); + List calendarDetailList = hotakeMeetingCalendarDetailMapper.selectHotakeMeetingCalendarDetailList(queryCalendarDetail); + + if(CollectionUtil.isNotEmpty(calendarDetailList)) { + //查询明细中的会议主表ID + List meetingIds = calendarDetailList.stream().map(HotakeMeetingCalendarDetail::getMeetingId).collect(Collectors.toList()); + hotakeMeetingCalendarInfo.setMeetingIds(meetingIds); + List calendarInfos = hotakeMeetingCalendarInfoMapper.selectHotakeMeetingCalendarInfoList(hotakeMeetingCalendarInfo); + if (CollectionUtil.isNotEmpty(calendarInfos)) { + //查询岗位数据 + HotakeRolesInfo query = new HotakeRolesInfo(); + List rolesInfoList = hotakeRolesInfoMapper.selectHotakeRolesInfoList(query); + + //查询岗位数据 + HotakeRolesApplyInfo queryApply = new HotakeRolesApplyInfo(); + List applyInfoList = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoList(queryApply); + //获取对应的参会人员数据 + HotakeMeetingCalendarDetail queryDetail = new HotakeMeetingCalendarDetail(); + List detailList = calendarDetailService.selectHotakeMeetingCalendarDetailList(queryDetail); + if (CollectionUtil.isNotEmpty(detailList)) { + Map> mapDetailList = detailList.stream().collect(Collectors.groupingBy(HotakeMeetingCalendarDetail::getMeetingId)); + SysUser queryUser = new SysUser(); + List userList = userService.selectUserList(queryUser); + for (HotakeMeetingCalendarInfo calendarInfo : calendarInfos) { + List calendarDetails = mapDetailList.get(calendarInfo.getId()); + for (HotakeMeetingCalendarDetail detail : calendarDetails) { + List users = userList.stream().filter(e -> e.getUserId() == detail.getCandidateId()).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(users)) { + detail.setCandidateUser(users.get(0)); + } + } + calendarInfo.setCalendarDetails(calendarDetails); + //返回岗位数据信息 + List applyInfos = applyInfoList.stream().filter(e->e.getId().longValue() == calendarInfo.getRoleApplyId().longValue()).toList(); + if(CollectionUtil.isNotEmpty(applyInfos)) { + HotakeRolesApplyInfo applyInfo = applyInfos.get(0); + List rolesInfos = rolesInfoList.stream().filter(e->e.getId().longValue() == applyInfo.getRoleId().longValue()).toList(); + if(CollectionUtil.isNotEmpty(rolesInfos)) { + HotakeRolesInfo rolesInfo = rolesInfos.get(0); + calendarInfo.setRolesInfo(rolesInfo); + } + } + } + } + } + return calendarInfos; + }else{ + return new ArrayList<>(); + } + + + + } + /** * 新增会议日历记录主 * @@ -262,7 +329,7 @@ public class HotakeMeetingCalendarInfoServiceImpl extends BaseServiceImpl implem calendarInfo.setMeetingName(meetingName); //保存主表数据 fill(FillTypeEnum.INSERT.getCode(), calendarInfo); - insertHotakeMeetingCalendarInfo(calendarInfo); + hotakeMeetingCalendarInfoMapper.insertHotakeMeetingCalendarInfo(calendarInfo); //保存明细数据 HotakeMeetingCalendarDetail hotakeMeetingCalendarDetail = new HotakeMeetingCalendarDetail(); hotakeMeetingCalendarDetail.setMeetingId(calendarInfo.getId()); @@ -279,4 +346,41 @@ public class HotakeMeetingCalendarInfoServiceImpl extends BaseServiceImpl implem } } } + + /** + * 查询当前候选者会议日历数据 + * @return + */ + @Override + public List selectHotakeMeetingCalendarDataDtoList() { + List dataDtos = new ArrayList<>(); + //根据候选者查询会议明细数据 + HotakeMeetingCalendarDetail queryCalendarDetail = new HotakeMeetingCalendarDetail(); + queryCalendarDetail.setCandidateId(SecurityUtils.getUserId()); + List calendarDetailList = hotakeMeetingCalendarDetailMapper.selectHotakeMeetingCalendarDetailList(queryCalendarDetail); + if(CollectionUtil.isNotEmpty(calendarDetailList)) { + HotakeMeetingCalendarInfo queryCalendarInfo = new HotakeMeetingCalendarInfo(); + //查询明细中的会议主表ID + List meetingIds = calendarDetailList.stream().map(HotakeMeetingCalendarDetail::getMeetingId).collect(Collectors.toList()); + queryCalendarInfo.setMeetingIds(meetingIds); + List calendarInfos = hotakeMeetingCalendarInfoMapper.selectHotakeMeetingCalendarInfoList(queryCalendarInfo); + if (CollectionUtil.isNotEmpty(calendarInfos)) { + //获取对应的参会人员数据 + Map> mapCalendarInfo = calendarInfos.stream().collect(Collectors.groupingBy(HotakeMeetingCalendarInfo::getMeetingDate)); + if(mapCalendarInfo != null) { + for(String key : mapCalendarInfo.keySet()) { + List calendarInfoList = mapCalendarInfo.get(key); + HotakeMeetingCalendarDataDto dataDto = new HotakeMeetingCalendarDataDto(); + dataDto.setMeetingDate(key); + dataDto.setMeetingFlag("1"); + dataDto.setNums(calendarInfoList.size()); + dataDtos.add(dataDto); + } + } + } + return dataDtos; + }else{ + return new ArrayList<>(); + } + } } diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeCvInfoMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeCvInfoMapper.xml index 4d41660..04777bc 100644 --- a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeCvInfoMapper.xml +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeCvInfoMapper.xml @@ -21,6 +21,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -31,7 +32,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select id, user_id, cv_name, cv_file_type, cv_url,file_size_show,cv_file_suffix, - status,cv_template_json,cv_score,cv_md5,experience,ai_match_score,ai_match_score_percentage, + status,cv_template_json,cv_score,cv_md5,experience,ai_match_score,ai_match_score_percentage,cv_optimize_json, del_flag, create_by, create_time, update_by, update_time, remark from hotake_cv_info @@ -70,6 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" experience, ai_match_score, ai_match_score_percentage, + cv_optimize_json, del_flag, create_by, @@ -93,6 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{experience}, #{aiMatchScore}, #{aiMatchScorePercentage}, + #{cvOptimizeJson}, #{delFlag}, #{createBy}, @@ -121,6 +124,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ai_match_score = #{aiMatchScore}, ai_match_score_percentage = #{aiMatchScorePercentage}, + cv_optimize_json = #{cvOptimizeJson}, + del_flag = #{delFlag}, create_by = #{createBy}, create_time = #{createTime}, diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeInitialScreeningQuestionsInfoMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeInitialScreeningQuestionsInfoMapper.xml index c1c1309..0b61628 100644 --- a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeInitialScreeningQuestionsInfoMapper.xml +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeInitialScreeningQuestionsInfoMapper.xml @@ -96,6 +96,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" delete from hotake_initial_screening_questions_info where id = #{id} + + delete from hotake_initial_screening_questions_info where role_id = #{roleId} + + delete from hotake_initial_screening_questions_info where id in diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeMeetingCalendarInfoMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeMeetingCalendarInfoMapper.xml index 21bbe51..51253be 100644 --- a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeMeetingCalendarInfoMapper.xml +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeMeetingCalendarInfoMapper.xml @@ -37,6 +37,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and meeting_date = #{meetingDate} and times = #{times} and status = #{status} + + and id in + + #{meetingId} + + diff --git a/vetti-system/src/main/java/com/vetti/system/service/impl/SysUserServiceImpl.java b/vetti-system/src/main/java/com/vetti/system/service/impl/SysUserServiceImpl.java index 16fad64..19fe49f 100644 --- a/vetti-system/src/main/java/com/vetti/system/service/impl/SysUserServiceImpl.java +++ b/vetti-system/src/main/java/com/vetti/system/service/impl/SysUserServiceImpl.java @@ -77,7 +77,7 @@ public class SysUserServiceImpl implements ISysUserService * @return 用户信息集合信息 */ @Override - @DataScope(deptAlias = "d", userAlias = "u") +// @DataScope(deptAlias = "d", userAlias = "u") public List selectUserList(SysUser user) { return userMapper.selectUserList(user); @@ -90,7 +90,7 @@ public class SysUserServiceImpl implements ISysUserService * @return 用户信息集合信息 */ @Override - @DataScope(deptAlias = "d", userAlias = "u") +// @DataScope(deptAlias = "d", userAlias = "u") public List selectAllocatedList(SysUser user) { return userMapper.selectAllocatedList(user); diff --git a/vetti-system/src/main/resources/mapper/system/SysUserMapper.xml b/vetti-system/src/main/resources/mapper/system/SysUserMapper.xml index a06c7bc..86837b7 100644 --- a/vetti-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/vetti-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -42,6 +42,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -71,7 +73,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status, r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status,u.sys_user_type ,u.steps,u.job_position,u.experience,u.cv_url,u.location,u.job_type,u.relocate,u.best_side_json,u.address, - u.user_flag,u.user_set_json,u.company_name,u.job_title + u.user_flag,u.user_set_json,u.company_name,u.job_title,u.user_oper_status from sys_user u left join sys_dept d on u.dept_id = d.dept_id left join sys_user_role ur on u.user_id = ur.user_id @@ -80,7 +82,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time,u.sys_user_type,u.steps,u.job_position,u.experience,u.cv_url,u.location, - u.job_type,u.relocate,u.best_side_json,u.address,u.user_flag,u.user_set_json,u.company_name,u.job_title + u.job_type,u.relocate,u.best_side_json,u.address,u.user_flag,u.user_set_json,u.company_name,u.job_title,u.user_oper_status from sys_user u left join sys_dept d on u.dept_id = d.dept_id left join sys_user_role ur on u.user_id = ur.user_id @@ -132,7 +134,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, - d.dept_name, d.leader,u.sys_user_type,u.steps,u.job_position,u.experience,u.cv_url,u.location,u.job_type,u.relocate,u.best_side_json,u.address,u.user_flag,u.user_set_json,u.company_name,u.job_title from sys_user u + d.dept_name, d.leader,u.sys_user_type,u.steps,u.job_position,u.experience,u.cv_url,u.location,u.job_type,u.relocate,u.best_side_json,u.address,u.user_flag,u.user_set_json,u.company_name,u.job_title,u.user_oper_status from sys_user u left join sys_dept d on u.dept_id = d.dept_id where u.del_flag = '0' @@ -114,7 +116,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time,u.sys_user_type, - u.steps,u.job_position,u.experience,u.cv_url,u.location,u.job_type,u.relocate,u.best_side_json,u.address,u.user_flag,u.user_set_json,u.company_name,u.job_title + u.steps,u.job_position,u.experience,u.cv_url,u.location,u.job_type,u.relocate,u.best_side_json,u.address,u.user_flag,u.user_set_json,u.company_name,u.job_title,u.user_oper_status from sys_user u left join sys_dept d on u.dept_id = d.dept_id left join sys_user_role ur on u.user_id = ur.user_id @@ -202,6 +204,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" company_name, job_title, + user_oper_status, create_time )values( @@ -234,6 +237,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{companyName}, #{jobTitle}, + #{userOperStatus}, sysdate() ) @@ -270,6 +274,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" company_name = #{companyName}, job_title = #{jobTitle}, + user_oper_status = #{userOperStatus}, update_time = sysdate()