Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package UMC.career_mate.domain.chatgpt.service;

import UMC.career_mate.domain.chatgpt.dto.api.response.ChatCompletionResponse;
import UMC.career_mate.domain.chatgpt.dto.request.ChatGPTRequestDTO;
import UMC.career_mate.domain.recruit.dto.MemberTemplateAnswerDTO;
import UMC.career_mate.domain.chatgpt.dto.api.request.GptRequest;
import UMC.career_mate.domain.chatgpt.dto.api.request.GptRequest.Message;
import UMC.career_mate.domain.recruit.enums.RecruitKeyword;
Expand Down Expand Up @@ -36,19 +36,18 @@ public class ChatGptService {

private static final String GPT_REQUEST_FORMAT_POSTFIX_FOR_RECRUIT_KEYWORD =
"이 사람의 직무를 내가 제시한 보기들 중에서 하나만 골라서 답변해줘.\n" +
"직무 보기 :'BACKEND', 'BACKEND_SPRING', 'BACKEND_NODE', 'BACKEND_DJANGO', 'FRONTEND', 'DESIGNER', 'PM', "
+
"직무 보기 :'BACKEND', 'BACKEND_SPRING', 'BACKEND_NODE', 'BACKEND_DJANGO', 'FRONTEND', 'DESIGNER', 'PM', " +
"이 중에서 적절한 직무가 없다면 'MISMATCH'로 답변해줘.\n" +
"앞뒤 설명하지 말고 직무만 답변해줘.";

private static final String GPT_REQUEST_FORMAT_PREFIX_FOR_COMMENT =
" = 사용자 이름이고, 다음 이력서 데이터를 기반으로 사용자의 강점을 어필할 수 있고, " +
"어떤 포지션이 어울리는지 어떤 경험을 어필하면 좋을지 그런 내용들로 추천 조언 문구를 생성해줘. " +
"'~~한 경험이 있는 000님, ~~한 경험을 어필해보면 어때요?', 또는 '~~포지에 지원해보 건 어떨까요? ~~에 강점을 드러낼 수 있을 것 같아요.'"
+
"와 비슷한 형식이지만 꼭 이런 형식이 아니더라도 너만의 스타일로 문구를 생성해줘." +
"말투는 \"입니다\"같은 딱딱말 말투는 사용하지 말고, \"요.\"같이 부드럽게 표현해줘. " +
"답변은 문구만 답변해줘. 문구를 생성할 때 이력서 데이터의 회사 이름은 제외해줘. 답변에서 엔터나 - 같은건 빼줘.";
private static final String GPT_REQUEST_FORMAT_FOR_COMMENT =
"위 경험 데이터를 기반으로 사용자의 이름을 문구에 포함해서 사용자의 강점을 어필할 수 있고, " +
"친근한 말투로 어떤 포지션이 어울리는지, 어떤 경험을 어필하면 좋을지와 같은 내용으로 조언 문구를 생성해서 답변해줘. " +
"답변은 문구만 답변해줘. 문구를 생성할 때 내용에는 회사 이름은 제외해줘. " +
"답변에서 '-'는 빼줘.";

private static final String GPT_SYSTEM_ROLE = "너는 취업 전문가로서 내가 보낸 경험 데이터를 기반으로 '~~한 경험이 있는 000님, ~~한 경험을 어필해보면 어때요?' 라는 느낌으로 사용자 맞춤형 추천 문구를 작성한다. " +
"문구의 말투는 '-니다'체를 사용하는 것이 아니라, '-요'체를 사용한다.";

public int getCareerYear(String chatGptRequestContent) {
GptRequest gptRequest = createGptRequest(
Expand All @@ -69,19 +68,23 @@ public RecruitKeyword getRecruitKeyword(String chatGptRequestContent) {
ObjectMapper om = new ObjectMapper();
String gptAnswer = getGptAnswer(om, gptRequest);

log.info("\ngptRequest : {}, gptAnswer : {} ", gptRequest, gptAnswer);
log.info("\ngptRequest : {}\ngptAnswer : {} ", gptRequest, gptAnswer);

return RecruitKeyword.getRecruitKeywordFromGptAnswerJob(gptAnswer);
}

public String getComment(ChatGPTRequestDTO chatGPTRequestDTO) {
GptRequest gptRequest = createGptRequest(
chatGPTRequestDTO.name() + GPT_REQUEST_FORMAT_PREFIX_FOR_COMMENT
+ chatGPTRequestDTO.content());
public String getComment(MemberTemplateAnswerDTO memberTemplateAnswerDTO) {
GptRequest gptRequest = createGptRequestWithSystemRole(
memberTemplateAnswerDTO.name() + "\n" + memberTemplateAnswerDTO.content()
+ GPT_REQUEST_FORMAT_FOR_COMMENT + memberTemplateAnswerDTO.content());

ObjectMapper om = new ObjectMapper();

return getGptAnswer(om, gptRequest);
String gptAnswer = getGptAnswer(om, gptRequest);

log.info("\ngptRequest : {}\ngptAnswer : {} ", gptRequest, gptAnswer);

return gptAnswer;
}

private GptRequest createGptRequest(String content) {
Expand All @@ -97,6 +100,24 @@ private GptRequest createGptRequest(String content) {
.build();
}

private GptRequest createGptRequestWithSystemRole(String content) {
Message systemMessage = Message.builder()
.role("system")
.content(GPT_SYSTEM_ROLE)
.build();

Message userMessage = Message.builder()
.role("user")
.content(content)
.build();

return GptRequest.builder()
.model("gpt-3.5-turbo")
.stream(false)
.messages(List.of(systemMessage, userMessage))
.build();
}

private String getGptAnswer(ObjectMapper om, GptRequest gptRequest) {
String requestBody = createRequestBody(om, gptRequest);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package UMC.career_mate.domain.recruit.converter;

import UMC.career_mate.domain.member.Member;
import UMC.career_mate.domain.recruit.Recruit;
import UMC.career_mate.domain.recruit.dto.FilterConditionDTO;
import UMC.career_mate.domain.recruit.dto.MemberTemplateAnswerDTO;
import UMC.career_mate.domain.recruit.dto.api.SaraminResponseDTO.Job;
import UMC.career_mate.domain.recruit.dto.response.RecommendRecruitDTO;
import UMC.career_mate.domain.recruit.dto.response.RecruitInfoDTO;
Expand Down Expand Up @@ -87,6 +89,13 @@ public static FilterConditionDTO toFilterConditionDTO(RecruitKeyword recruitKeyw
.build();
}

public static MemberTemplateAnswerDTO toMemberTemplateAnswerDTO(Member member, String content) {
return MemberTemplateAnswerDTO.builder()
.name("이름 : " + member.getName())
.content(content)
.build();
}

private static String formatDeadLine(Recruit recruit) {
LocalDate today = LocalDate.now();
LocalDate targetDate = recruit.getDeadLine().toLocalDate();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package UMC.career_mate.domain.recruit.dto;

import lombok.Builder;

@Builder
public record MemberTemplateAnswerDTO(
String name,
String content
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import UMC.career_mate.domain.answer.Answer;
import UMC.career_mate.domain.answer.repository.AnswerRepository;
import UMC.career_mate.domain.chatgpt.GptAnswer;
import UMC.career_mate.domain.chatgpt.dto.request.ChatGPTRequestDTO;
import UMC.career_mate.domain.recruit.dto.MemberTemplateAnswerDTO;
import UMC.career_mate.domain.chatgpt.service.GptAnswerCommandService;
import UMC.career_mate.domain.recruit.dto.FilterConditionDTO;
import UMC.career_mate.domain.chatgpt.repository.GptAnswerRepository;
Expand Down Expand Up @@ -58,6 +58,7 @@ public class RecruitQueryService {
private final static String INTERN_PREFIX = "인턴 경험 데이터 : ";
private final static String PROJECT_QUESTION_CONTENT_PERIOD = "기간";
private final static String INTERN_QUESTION_CONTENT_PERIOD = "근무기간";
private final static String TEMPLATE_ANSWER_IS_NULL_OR_EMPTY_COMMENT = "프로젝트 또는 인턴 템플릿에 대해 답변을 작성하고, Chat GPT의 코멘트를 받아보세요!";

public PageResponseDTO<List<RecommendRecruitDTO>> getRecommendRecruitList(int page, int size,
RecruitSortType recruitSortType, Member member) {
Expand All @@ -80,10 +81,7 @@ public RecruitInfoDTO findRecruitInfo(Member member, Long recruitId) {
Recruit recruit = recruitRepository.findById(recruitId)
.orElseThrow(() -> new GeneralException(CommonErrorCode.NOT_FOUND_RECRUIT));

// TODO: db에서 사용자의 템플릿 데이터 가져오는걸로 수정
ChatGPTRequestDTO chatGPTRequestDTO = createDummyData(member);

String comment = chatGptService.getComment(chatGPTRequestDTO);
String comment = createComment(member);

return RecruitConverter.toRecruitInfoDTO(comment, recruit);
}
Expand Down Expand Up @@ -204,6 +202,39 @@ private RecruitKeyword calculateRecruitKeyword(Member member) {
return recruitKeyword;
}

private String createComment(Member member) {
Job job = member.getJob();

Map<TemplateType, List<Answer>> templateTypeByAnswers = getTemplateTypeByAnswers(member,
job);

List<Answer> projectAnswers = templateTypeByAnswers.getOrDefault(
TemplateType.PROJECT_EXPERIENCE, List.of());
List<Answer> internAnswers = templateTypeByAnswers.getOrDefault(
TemplateType.INTERN_EXPERIENCE, List.of());

if (projectAnswers.isEmpty() && internAnswers.isEmpty()) {
log.info("(프로젝트, 인턴) 템플릿 답변 없이, 채용 공고 요약 페이지 조회하는 경우 -> answer 생성 안된 경우");
return TEMPLATE_ANSWER_IS_NULL_OR_EMPTY_COMMENT;
}

StringBuilder contentBuilder = new StringBuilder();
int projectEnterCnt = createChatGptRequestContent(contentBuilder, projectAnswers,
PROJECT_PREFIX, PROJECT_QUESTION_CONTENT_PERIOD);
int internEnterCnt = createChatGptRequestContent(contentBuilder, internAnswers,
INTERN_PREFIX, INTERN_QUESTION_CONTENT_PERIOD);

if (isEmptyContentBuilder(contentBuilder, projectEnterCnt, internEnterCnt)) {
log.info("최종 데이터가 기본 틀 데이터를 제외하고 빈 문자열인 경우");
return TEMPLATE_ANSWER_IS_NULL_OR_EMPTY_COMMENT;
}

MemberTemplateAnswerDTO memberTemplateAnswerDTO = RecruitConverter.toMemberTemplateAnswerDTO(
member, contentBuilder.toString());

return chatGptService.getComment(memberTemplateAnswerDTO);
}

private Map<TemplateType, List<Answer>> getTemplateTypeByAnswers(Member member, Job job) {
List<Answer> findAnswers = answerRepository.findByMemberAndTemplateTypesAndJob(member,
List.of(TemplateType.PROJECT_EXPERIENCE, TemplateType.INTERN_EXPERIENCE), job);
Expand Down Expand Up @@ -253,12 +284,4 @@ private PageResponseDTO<List<RecommendRecruitDTO>> createPageResponseDTO(int pag
.result(recommendRecruitDTOList)
.build();
}

private ChatGPTRequestDTO createDummyData(Member member) {
return ChatGPTRequestDTO.builder()
.name(member.getName())
.content(
"네이버 / 백엔드 개발팀, 백엔드 개발자, 2023.06.01~2023.12.01, Spring 대규모 데이터 처리 및 최적화 과정을 통해 성능 개선의 중요성을 배웠습니다., 사용자 데이터를 기반으로 한 개인화 서비스 개발에 참여하며, 데이터의 가치를 깊이 이해할 수 있었습니다., 대규모 시스템 아키텍처 설계 경험을 통해 기술적인 자신감이 크게 향상되었습니다.")
.build();
}
}