Skip to content

Commit

Permalink
Merge pull request #45 from KUSITMS-29th-TEAM-D/feature/#43/discover-…
Browse files Browse the repository at this point in the history
…persona

[feat] : 돌아보기 페르소나 공감 & 요약 API 구현 (POST)
  • Loading branch information
bbbang105 authored May 19, 2024
2 parents bc59655 + fbadbec commit efcd310
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import kusitms.jangkku.domain.clova.dto.ClovaDto;

public interface ClovaService {
String requestWebClient(ClovaDto.ChatBotRequestDto request);
String createDesignPersona(String message);
String createDiscoverPersonaReaction(String message);
String createDiscoverPersonaSummary(String message);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,33 @@ public class ClovaServiceImpl implements ClovaService {
private String apiGatewayKey;
private final WebClient webClient;

// 설계하기 페르소나를 CLOVA로 생성하는 메서드
@Override
public String createDesignPersona(String message) {
ClovaDto.ChatBotRequestDto request = ClovaDto.ChatBotRequestDto.DesignPersonaRequestOf();
request.getMessages().add(Message.creatUserOf(message));

return requestWebClient(request);
}

// 돌아보기 페르소나 공감을 생성하는 메서드
@Override
public String createDiscoverPersonaReaction(String message) {
ClovaDto.ChatBotRequestDto request = ClovaDto.ChatBotRequestDto.DiscoverPersonaReactionRequestOf();
request.getMessages().add(Message.creatUserOf(message));

return requestWebClient(request);
}

// 돌아보기 페르소나 요약을 생성하는 메서드
@Override
public String createDiscoverPersonaSummary(String message) {
ClovaDto.ChatBotRequestDto request = ClovaDto.ChatBotRequestDto.DiscoverPersonaSummaryRequestOf();
request.getMessages().add(Message.creatUserOf(message));

return requestWebClient(request);
}

// CLOVA와 통신하여 답변을 가져오는 메서드
public String requestWebClient(ClovaDto.ChatBotRequestDto request) {
ClovaDto.ChatBotResponse message = webClient.post()
Expand All @@ -34,14 +61,4 @@ public String requestWebClient(ClovaDto.ChatBotRequestDto request) {

return message.getResult().getMessage().getContent();
}

// 설계하기 페르소나를 CLOVA로 생성하는 메서드
public String createDesignPersona(String message) {
ClovaDto.ChatBotRequestDto request = ClovaDto.ChatBotRequestDto.DesignPersonaRequestOf();
request.getMessages().add(Message.creatUserOf(message));
String designPersonaResult = requestWebClient(request);
System.out.println(designPersonaResult);

return designPersonaResult;
}
}
25 changes: 19 additions & 6 deletions src/main/java/kusitms/jangkku/domain/clova/dto/ClovaDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,40 @@ public static class ChatBotRequestDto {
private int maxTokens;
private double repeatPenalty;

public static ChatBotRequestDto defaultOf() {
public static ChatBotRequestDto DesignPersonaRequestOf() {
ArrayList<Message> messages = new ArrayList<>();
messages.add(Message.createDefaultOf());
messages.add(Message.createDesignPersonaSystemOf());

return ChatBotRequestDto.builder()
.messages(messages)
.topP(0.8)
.temperature(0.5)
.temperature(0.3)
.maxTokens(256)
.repeatPenalty(5.0)
.build();
}

public static ChatBotRequestDto DesignPersonaRequestOf() {
public static ChatBotRequestDto DiscoverPersonaReactionRequestOf() {
ArrayList<Message> messages = new ArrayList<>();
messages.add(Message.createDesignPersonaSystemOf());
messages.add(Message.createReactionOf());

return ChatBotRequestDto.builder()
.messages(messages)
.topP(0.8)
.temperature(0.3)
.maxTokens(256)
.repeatPenalty(5.0)
.build();
}

public static ChatBotRequestDto DiscoverPersonaSummaryRequestOf() {
ArrayList<Message> messages = new ArrayList<>();
messages.add(Message.createSummaryOf());

return ChatBotRequestDto.builder()
.messages(messages)
.topP(0.8)
.temperature(0.5)
.temperature(0.3)
.maxTokens(256)
.repeatPenalty(5.0)
.build();
Expand Down
49 changes: 28 additions & 21 deletions src/main/java/kusitms/jangkku/domain/clova/dto/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,6 @@ public static Message creatSystemOf(String content) {
.build();
}

public static Message createDefaultOf() {
return Message.builder()
.role(Message.ROLE.system)
.content("아래는 CLOVA가 지켜야 할 규칙입니다.\r\n1. 당신은 사람들의 강점과 특징을 파악하는 역할을 합니다." +
"\r\n2. CLOVA의 처음 시작은 무조건 \"안녕\r\n나는 네가 과거에 어떤 사람이었는지 탐색하는 과정을 함께할 셀피스봇이야." +
"\r\n너만의 고유한 조각을 찾을 수 있도록 도와줄게! 그럼 한번 시작해볼까?\" 라는 텍스트로 시작합니다. 다른말은 안돼요." +
"\r\n3. 첫 인사가 끝나면 하단의 <질문 리스트> 중 무작위로 1개를 뽑아User에게 질문해주세요. 총 3개의 질문을 해주면 됩니다. " +
"\r\n위의 질문 말고 다른 질문은 안돼요.\r\n4. user가 질문에 답한다면, 사용자의 질문을 요약하며 공감한 후 다음 질문을 수행합니다." +
"\r\n6. 말투는 친구처럼 다정하고 친근한 말투로 반말을 사용한다." +
"\r\n7. 3개의 질문이 끝나면 사람들이 입력한 답변을 통해 해당 사람의 특징을 파악한 후 3가지 단어로 알려주세요. " +
"\r\n\r\n<질문 리스트>\r\n- 너에게 사랑이란 무엇을 의미해?\r\n- 너는 사랑에서 어떤 유형의 관계를 원해?" +
"\r\n- 사랑하는 사람과의 관계에서 가장 중요하게 생각하는 것은 뭐야?\r\n- 지난 사랑 경험에서 얻은 가장 큰 교훈은 뭐야?" +
"\r\n- 앞으로 어떤 방식으로 사랑을 키우고 싶어?아래는 AI 스피커 CLOVA와 사용자의 대화예시입니다. " +
"\r\n\r\n사용자 : 안녕\r\nCLOVA : 안녕. 나는 네가 과거에 어떤 사람이었는지 탐색하는 과정을 함께할 셀피스봇이야. 너만의 고유한 조각을 찾을 수 있도록 도와줄게! 그럼 한번 시작해볼까? 너에게 사랑이란 무엇을 의미해?" +
"\r\n사용자 : 나에게 사랑은 풍선껌이야\r\nCLOVA : 풍선껌처럼 달콤하면서도 잠시의 즐거움을 줄 수 있는 사랑을 선호하는구나. 그럼 어떤 유형의 관계를 원해?" +
"\r\n사용자 : 나는 친구같은 관계를 원해\r\nCLOVA : 친구처럼 편안하고 서로를 이해하는 관계를 원하는 거군. 그럼 사랑하는 사람과의 관계에서 가장 중요하게 생각하는 것은 뭐야?" +
"\r\n사용자 : 믿음이 가장 중요하다고 생각해.\r\nCLOVA : 믿음을 가장 중요하게 생각하는구나. 이해관계를 통해 비로소 진정성 있는 사랑이 만들어지겠지. 지금까지 나눈 이야기를 종합해보면 너는 배려심이 깊고 따뜻한 마음을 가진 사람인 것 같아. " +
"\r\n** 배려, 따뜻함, 믿음 **")
.build();
}

public static Message createDesignPersonaSystemOf() {
return Message.builder()
.role(Message.ROLE.system)
Expand All @@ -74,4 +53,32 @@ public static Message createDesignPersonaSystemOf() {
"\"다양한 취미활동을 즐기며 새로운 것에 도전해 나만의 개성있는 콘텐츠를 제작하는 '취미부자 유튜버'\"")
.build();
}

public static Message createReactionOf() {
return Message.builder()
.role(Message.ROLE.system)
.content("너는 지금 사용자와 1대1로 진솔하게 대화를 하는 챗봇이야.\n" +
"너가 질문을 했다는 가정하에, 사용자가 답변을 할 거야.\n" +
"이제 그거에 대한 공감을 해주면 돼. 친절한 말투로 해줘. 그리고 조금 더 친구와 공감하듯이 말투를 딱딱하지 않게 해줘. 상대방이 말한 것에 대해서 요약을 해준 다음에, 너가 말을 해줘.\n" +
"아래는 예시야.\n" +
"\n" +
"사용자 : 나는 사랑이 솜사탕 같다고 생각을 해.\n" +
"시스템 : 사랑이 솜사탕 같다고 생각하시는군요! 부드럽고 달콤해서 행복감을 주지만, 녹아내려서 사라지는 모습이 닮아서 그렇게 느끼시는 걸 수도 있겠네요.")
.build();
}

public static Message createSummaryOf() {
return Message.builder()
.role(Message.ROLE.system)
.content("너는 지금 사용자와 1대1로 진솔하게 대화를 하는 챗봇이야.\n" +
"너가 질문을 했다는 가정하에, 사용자가 답변을 할 거야.\n" +
"이제 그거에 대한 요약을 해주면 돼. 아래는 예시야.\n" +
"예시처럼 받침이 \"\"으로 끝나도록 해줘야 해.\n" +
"그리고 요약을 상대방의 입장에서 해줘야 돼. \n" +
"\"~라고 생각함\" 또는 \"~라고 답변함\" 이런 식으로.\n" +
"\n" +
"사용자 : 나는 사랑이 솜사탕 같다고 생각을 해.\n" +
"시스템 : 사랑을 솜사탕 같다고 생각함.")
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,25 @@
public class DiscoverPersonaController {
private final DiscoverPersonaService discoverPersonaService;

// 설계하기 페르소나를 조회하는 API
// 돌아보기 페르소나 질문을 응답 받는 API
@GetMapping("/discover/question")
public ResponseEntity<ApiResponse<DiscoverPersonaDto.QuestionResponse>> getDesignPersona(
public ResponseEntity<ApiResponse<DiscoverPersonaDto.QuestionResponse>> getNewQuestion(
@RequestHeader("Authorization") String authorizationHeader,
@RequestParam("category") String category) {

DiscoverPersonaDto.QuestionResponse questionResponse = discoverPersonaService.getNewQuestion(authorizationHeader, category);

return ApiResponse.onSuccess(PersonaSuccessStatus.GET_NEW_QUESTION, questionResponse);
return ApiResponse.onSuccess(PersonaSuccessStatus.CREATED_NEW_QUESTION, questionResponse);
}

// 돌아보기 페르소나 공감 & 요약을 응답 받는 API
@PostMapping("/discover/answer")
public ResponseEntity<ApiResponse<DiscoverPersonaDto.AnswerResponse>> getReactionAndSummary(
@RequestHeader("Authorization") String authorizationHeader,
@RequestBody DiscoverPersonaDto.AnswerRequest answerRequest) {

DiscoverPersonaDto.AnswerResponse answerResponse = discoverPersonaService.getReactionAndSummary(authorizationHeader, answerRequest);

return ApiResponse.onSuccess(PersonaSuccessStatus.CREATED_REACTION_AND_SUMMARY, answerResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

public interface DiscoverPersonaService {
DiscoverPersonaDto.QuestionResponse getNewQuestion(String authorizationHeader, String category);
}
DiscoverPersonaDto.AnswerResponse getReactionAndSummary(String authorizationHeader, DiscoverPersonaDto.AnswerRequest answerRequest);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package kusitms.jangkku.domain.persona.application;

import kusitms.jangkku.domain.clova.application.ClovaService;
import kusitms.jangkku.domain.persona.constant.Question;
import kusitms.jangkku.domain.persona.dao.DiscoverPersonaChattingRepository;
import kusitms.jangkku.domain.persona.dao.DiscoverPersonaRepository;
Expand All @@ -25,6 +26,7 @@
public class DiscoverPersonaServiceImpl implements DiscoverPersonaService {
private final JwtUtil jwtUtil;
private final NumberUtil numberUtil;
private final ClovaService clovaService;
private final UserRepository userRepository;
private final DiscoverPersonaRepository discoverPersonaRepository;
private final DiscoverPersonaChattingRepository discoverPersonaChattingRepository;
Expand Down Expand Up @@ -68,6 +70,28 @@ public DiscoverPersonaDto.QuestionResponse getNewQuestion(String authorizationHe
return DiscoverPersonaDto.QuestionResponse.of(newDiscoverPersonaChatting.getId(), newQuestionContent);
}

// 공감과 요약을 생성해 응답하는 메서드
@Override
public DiscoverPersonaDto.AnswerResponse getReactionAndSummary(String authorizationHeader, DiscoverPersonaDto.AnswerRequest answerRequest) {
String token = jwtUtil.getTokenFromHeader(authorizationHeader);
UUID userId = UUID.fromString(jwtUtil.getUserIdFromToken(token));
User user = userRepository.findByUserId(userId)
.orElseThrow(() -> new UserException(UserErrorResult.NOT_FOUND_USER));

DiscoverPersonaChatting discoverPersonaChatting = discoverPersonaChattingRepository.findById(answerRequest.getChattingId())
.orElseThrow(() -> new PersonaException(PersonaErrorResult.NOT_FOUND_CHATTING));

String reaction = clovaService.createDiscoverPersonaReaction(answerRequest.getAnswer());
String summary = clovaService.createDiscoverPersonaSummary(answerRequest.getAnswer());

discoverPersonaChatting.updateAnswer(answerRequest.getAnswer());
discoverPersonaChatting.updateReaction(reaction);
discoverPersonaChatting.updateSummary(summary);
discoverPersonaChattingRepository.save(discoverPersonaChatting);

return DiscoverPersonaDto.AnswerResponse.of(reaction, summary);
}

// 질문 번호를 생성하는 메서드
private int createNewQuestionNumber(List<Integer> questionNumbers) {
int randomQuestionNumber = numberUtil.getRandomNumberNotInList(questionNumbers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
@AllArgsConstructor
public enum PersonaSuccessStatus implements BaseCode {
// 돌아보기 페르소나
GET_NEW_QUESTION(HttpStatus.CREATED, "201", "돌아보기 페르소나 질문 생성에 성공했습니다."),
CREATED_NEW_QUESTION(HttpStatus.CREATED, "201", "돌아보기 페르소나 질문 생성에 성공했습니다."),
CREATED_REACTION_AND_SUMMARY(HttpStatus.CREATED, "201", "돌아보기 페르소나 공감 & 요약 생성에 성공했습니다."),
// 정의하기 페르소나
CREATED_DEFINE_PERSONA(HttpStatus.CREATED, "201", "정의하기 페르소나 생성에 성공했습니다."),
GET_DEFINE_PERSONA(HttpStatus.OK, "200", "정의하기 페르소나 조회에 성공했습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@ public DiscoverPersonaChatting(DiscoverPersona discoverPersona, int questionNumb
this.reaction = reaction;
this.summary = summary;
}
public void updateAnswer(String answer) {
this.answer = answer;
}
public void updateReaction(String reaction) {
this.reaction = reaction;
}

public void updateSummary(String summary) {
this.summary = summary;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,33 @@ public static DiscoverPersonaDto.QuestionResponse of(Long chattingId, String que
.build();
}
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class AnswerRequest {
private Long chattingId;
private String answer;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class AnswerResponse {
private String reaction;
private String summary;

public static DiscoverPersonaDto.AnswerResponse of(String reaction, String summary) {
return DiscoverPersonaDto.AnswerResponse.builder()
.reaction(reaction)
.summary(summary)
.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public enum PersonaErrorResult implements BaseErrorCode {
NOT_FOUND_PERSONA_TYPE(HttpStatus.NOT_FOUND, "404", "존재하지 않는 페르소나 타입입니다."),
NOT_FOUND_DEFINE_PERSONA(HttpStatus.NOT_FOUND, "404", "정의하기 페르소나가 존재하지 않습니다."),
IS_ALREADY_COMPLETED(HttpStatus.CONFLICT, "409", "이미 답변이 종료된 카테고리입니다."),
NOT_FOUND_QUESTION(HttpStatus.NOT_FOUND, "404", "존재하지 않는 질문입니다.");
NOT_FOUND_QUESTION(HttpStatus.NOT_FOUND, "404", "존재하지 않는 질문입니다."),
NOT_FOUND_CHATTING(HttpStatus.NOT_FOUND, "404", "존재하지 않는 채팅입니다.");

private final HttpStatus httpStatus;
private final String code;
Expand Down

0 comments on commit efcd310

Please sign in to comment.