Skip to content

Commit

Permalink
Merge pull request #19 from Alpha-mon/18-fix-test-code-of-chatbot-use…
Browse files Browse the repository at this point in the history
…-pagination

18 fix test code of chatbot use pagination
  • Loading branch information
megymj authored Sep 23, 2023
2 parents d332ad7 + ca56d32 commit 201308f
Show file tree
Hide file tree
Showing 17 changed files with 761 additions and 747 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package org.ai.roboadvisor.domain.chat.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "채팅 대화 내역 삭제를 요청할 때 사용하는 JSON 요청 예시")
public class ClearRequest {

@Schema(description = "사용자 정보: 닉네임", example = "testUser")
@NotBlank
private String nickname;

public static ClearRequest of(String nickname) {
return new ClearRequest(nickname);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@Getter
@NoArgsConstructor
public class ChatListResponse {
public class ChatOrderResponse {
private Integer order;
private String role;
private String content;
Expand All @@ -19,15 +19,15 @@ public class ChatListResponse {
private LocalDateTime time;

@Builder
private ChatListResponse(Integer order, String role, String content, LocalDateTime time) {
private ChatOrderResponse(Integer order, String role, String content, LocalDateTime time) {
this.order = order;
this.role = role;
this.content = content;
this.time = time;
}

public static ChatListResponse fromChatEntity(Chat chat, Integer order) {
return ChatListResponse.builder()
public static ChatOrderResponse fromChatEntity(Chat chat, Integer order) {
return ChatOrderResponse.builder()
.order(order)
.role(chat.getRole())
.content(chat.getMessage())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.ai.roboadvisor.domain.chat.dto.response;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Getter
@NoArgsConstructor
public class ChatResult {

@JsonInclude(JsonInclude.Include.NON_NULL) // This will ignore property if it's null
private List<ChatOrderResponse> chatOrderResponse;

@JsonInclude(JsonInclude.Include.NON_NULL) // This will ignore property if it's null
private ChatResponse chatResponse;

public ChatResult(List<ChatOrderResponse> chatOrderResponse) {
this.chatOrderResponse = chatOrderResponse;
this.chatResponse = null;
}

public ChatResult(ChatResponse chatResponse) {
this.chatOrderResponse = null;
this.chatResponse = chatResponse;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface ChatRepository extends MongoRepository<Chat, String> {

boolean existsChatByNickname(String nickname);

@Query(value = "{ 'email' : ?0 }", delete = true)
long deleteAllByEmail(String email);
@Query(value = "{ 'nickname' : ?0 }", delete = true)
long deleteAllByNickname(String nickname);

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import org.ai.roboadvisor.domain.chat.dto.request.ChatGptRequest;
import org.ai.roboadvisor.domain.chat.dto.request.MessageRequest;
import org.ai.roboadvisor.domain.chat.dto.response.ChatGptResponse;
import org.ai.roboadvisor.domain.chat.dto.response.ChatListResponse;
import org.ai.roboadvisor.domain.chat.dto.response.ChatOrderResponse;
import org.ai.roboadvisor.domain.chat.dto.response.ChatResponse;
import org.ai.roboadvisor.domain.chat.dto.response.ChatResult;
import org.ai.roboadvisor.domain.chat.entity.Chat;
import org.ai.roboadvisor.domain.chat.repository.ChatRepository;
import org.ai.roboadvisor.global.exception.CustomException;
Expand All @@ -27,8 +28,6 @@
import java.util.List;
import java.util.Optional;

import static org.ai.roboadvisor.global.exception.ErrorIntValue.*;

@Slf4j
@RequiredArgsConstructor
@Service
Expand All @@ -46,13 +45,12 @@ public class ChatService {
private String OPEN_AI_MODEL;

@Transactional
public List<ChatListResponse> getAllChatOfUser(String nickname) {
List<ChatListResponse> result = new ArrayList<>();

if (!checkIfChatIsExistsInDb(nickname)) {
ChatListResponse chatResponse = createAndSaveWelcomeMessage(nickname);
result.add(chatResponse);
public ChatResult getAllChats(String nickname) {
if (!checkIfChatExistsInDb(nickname)) {
return new ChatResult(createAndSaveWelcomeMessage(nickname));
} else {
List<ChatOrderResponse> result = new ArrayList<>();

// 1. Sorting Data order by time and _id
Sort sort = Sort.by(
Sort.Order.desc("time"),
Expand All @@ -66,29 +64,20 @@ public List<ChatListResponse> getAllChatOfUser(String nickname) {
for (int i = 0; i < chatList.size(); i++) {
Chat thisChat = chatList.get(i);
thisChat.setTimeZone(thisChat.getTime(), UTC_TO_KST); // UTC -> KST
ChatListResponse dto = ChatListResponse.fromChatEntity(chatList.get(i), chatList.size() - i);
ChatOrderResponse dto = ChatOrderResponse.fromChatEntity(chatList.get(i), chatList.size() - i);
result.add(dto);
}
return new ChatResult(result);
}
return result;
}

public int saveChat(MessageRequest messageRequest) {

public void save(MessageRequest messageRequest) {
// MessageRequest time format 검증
Optional<LocalDateTime> dateTimeOptional = parseDateTime(messageRequest.getTime());
if (dateTimeOptional.isEmpty()) {
return TIME_INPUT_INVALID.getValue(); // or handle the error differently
}
LocalDateTime dateTime = parseDateTime(messageRequest.getTime())
.orElseThrow(() -> new CustomException(ErrorCode.TIME_INPUT_INVALID));

Chat userChat = MessageRequest.toChatEntity(messageRequest, dateTimeOptional.get());
try {
userChat.setTimeZone(userChat.getTime(), KST_TO_UTC); // KST -> UTC
chatRepository.save(userChat);
return SUCCESS.getValue();
} catch (RuntimeException e) {
return INTERNAL_SERVER_ERROR.getValue();
}
Chat userChat = MessageRequest.toChatEntity(messageRequest, dateTime);
saveChat(userChat);
}

public ChatResponse getMessageFromApi(String nickname, String message) {
Expand Down Expand Up @@ -134,17 +123,17 @@ public ChatResponse getMessageFromApi(String nickname, String message) {
}
}

public boolean clear(String email) {
public ChatResult clear(String nickname) {
// Clear All data
try {
chatRepository.deleteAllByEmail(email);
return true;
chatRepository.deleteAllByNickname(nickname);
} catch (RuntimeException e) {
return false;
throw new CustomException(ErrorCode.INTERNAL_SERVER_ERROR);
}
return new ChatResult(createAndSaveWelcomeMessage(nickname));
}

public ChatListResponse createAndSaveWelcomeMessage(String nickname) {
public ChatResponse createAndSaveWelcomeMessage(String nickname) {
String WELCOME_MESSAGE = "안녕하세요, 저는 AI로보어드바이저의 ChatGPT 서비스에요! 궁금한 점을 입력해주세요";

// 1. Create Chat Entity and Save
Expand All @@ -156,16 +145,20 @@ public ChatListResponse createAndSaveWelcomeMessage(String nickname) {
.time(now)
.build();

saveChat(chat);

// 2. Entity -> DTO and Return Welcome Message
return ChatResponse.fromChatEntity(chat);
}

private void saveChat(Chat chat) {
try {
chat.setTimeZone(chat.getTime(), KST_TO_UTC); // KST -> UTC
chatRepository.save(chat);
chat.setTimeZone(chat.getTime(), UTC_TO_KST); // UTC -> KST
} catch (RuntimeException e) {
throw new CustomException(ErrorCode.INTERNAL_SERVER_ERROR);
}

// 2. Entity -> DTO and Return Welcome Message
return ChatListResponse.fromChatEntity(chat, null);
}

private Optional<LocalDateTime> parseDateTime(String timeString) {
Expand All @@ -178,7 +171,7 @@ private Optional<LocalDateTime> parseDateTime(String timeString) {
}
}

private boolean checkIfChatIsExistsInDb(String email) {
private boolean checkIfChatExistsInDb(String email) {
return chatRepository.existsChatByNickname(email);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.ai.roboadvisor.domain.chat.swagger_annotation.clear;

import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.ai.roboadvisor.global.common.dto.SuccessApiResponse;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@ApiResponse(responseCode = "201", description = "기존에 대화 내용을 모두 삭제한 뒤, 다시 초기 응답을 보내준다",
content = @Content(schema = @Schema(implementation = SuccessApiResponse.class),
examples = @ExampleObject(name = "example", description = "정상 응답 예시",
value = """
{
"code": 201,
"message": "기존 대화 내용이 정상적으로 삭제되었습니다",
"data": [
{
"order": null,
"role": "assistant",
"content": "안녕하세요, 저는 AI로보어드바이저의 ChatGPT 서비스에요! 궁금한 점을 입력해주세요",
"time": "2023-09-15 00:43:36"
}
]
}
"""
)))
public @interface clear_CREATED {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.ai.roboadvisor.domain.chat.swagger_annotation.getAllChats;

import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.ai.roboadvisor.global.common.dto.SuccessApiResponse;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@ApiResponse(responseCode = "201", description = "사용자가 채팅방에 처음 입장한 경우, 챗봇의 Welcome Message를 보낸다.",
content = @Content(schema = @Schema(implementation = SuccessApiResponse.class),
examples = @ExampleObject(name = "example",
description = "처음 입장한 경우 응답 예시",
value = """
{
"code": 201,
"message": "채팅방 입장에 성공하셨습니다",
"data": {
"chatResponse": {
"role": "assistant",
"content": "안녕하세요, 저는 AI로보어드바이저의 ChatGPT 서비스에요! 궁금한 점을 입력해주세요",
"time": "2023-09-22 14:32:58"
}
}
}
"""
)))
public @interface getAllChats_CREATED {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.ai.roboadvisor.domain.chat.swagger_annotation.getAllChats;

import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.ai.roboadvisor.global.common.dto.SuccessApiResponse;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@ApiResponse(responseCode = "200", description = """
사용자가 채팅방에 처음 입장한 경우, 기존의 대화 내용을 보낸다.
chatOrderResponse Array 객체 안에, order, role, content, time 정보가 각각 담긴다.
order 값이 높을 수록, 나중에 작성된 메시지이다. 따라서 order 값을 기준으로 정렬하면 되며,
혹은 time 값을 DateTime 타입으로 바꿔서 정렬도 가능하다.
'현재는 Pagination을 따로 사용하지 않고, 전체 데이터를 한 번에 모두 보내도록 구현되어 있음'
""",
content = @Content(schema = @Schema(implementation = SuccessApiResponse.class),
examples = @ExampleObject(name = "example",
description = "처음 입장한 경우 응답 예시",
value = """
{
"code": 200,
"message": "기존 대화 내용을 정상적으로 불러왔습니다",
"data": {
"chatOrderResponse": [
{
"order": 3,
"role": "assistant",
"content": "선물거래는 주식 시장에서 특정 종목의 주식을 향후에 일정 가격으로 매매하는 거래 방식을 의미합니다. 주식을 선물로 거래하기 때문에 선물거래라고 불립니다. 예를 들어, 현재 시점에서 어떤 주식의 가격이 100원인데, 선물거래를 통해 이 주식을 3개월 후에 120원에 구매하거나 판매하는 것이 가능합니다. 선물거래는 주식을 장기적으로 보유하거나 투자자들이 가격 변동에 대한 위험을 헷지하기 위해 사용될 수 있습니다.",
"time": "2023-09-22 14:30:57"
},
{
"order": 2,
"role": "assistant",
"content": "안녕하세요, 저는 AI로보어드바이저의 ChatGPT 서비스에요! 궁금한 점을 입력해주세요",
"time": "2023-09-22 14:24:11"
},
{
"order": 1,
"role": "user",
"content": "주식에서 선물거래의 의미는 무엇이니?",
"time": "2023-09-22 01:28:20"
}
]
}
}
"""
)))
public @interface getAllChats_OK {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.ai.roboadvisor.domain.chat.swagger_annotation.sendMessage;

import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.ai.roboadvisor.global.common.dto.SuccessApiResponse;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@ApiResponse(responseCode = "400", description = """
시간 형식을 잘못 입력한 경우
e.g) 2023-03-03 11:11:11 (사이에 띄어쓰기가 두 칸인 경우), 2023-03-03T11:11:11 (사이에 문자가 끼워져 있는 경우), ...
""",
content = @Content(schema = @Schema(implementation = SuccessApiResponse.class),
examples = @ExampleObject(name = "example",
description = "시간 형식을 잘못 입력한 경우 예시",
value = """
{
"code": 400,
"message": "time 형식을 yyyy-MM-dd HH:mm:ss으로 작성해 주세요",
"data": null
}
"""
)))
public @interface sendMessage_BAD_REQUEST {
}
Loading

0 comments on commit 201308f

Please sign in to comment.