From 52dd8da7a936d089a53b7bdc524b6c3b4c2ecdde Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Sat, 25 Jan 2025 16:22:41 +0900 Subject: [PATCH 01/13] =?UTF-8?q?Feat=20:=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index a6ff133..418e629 100644 --- a/build.gradle +++ b/build.gradle @@ -84,6 +84,9 @@ dependencies { // amazon s3 implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' + //spring AI + implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter:1.0.0-SNAPSHOT' + } clean { delete file('src/main/generated')} From bf85185f0bd75531925cc395b8935547981307ab Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Sat, 25 Jan 2025 17:28:16 +0900 Subject: [PATCH 02/13] =?UTF-8?q?Feat=20:=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=ED=82=A4=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++-- src/main/resources/application.yml | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 418e629..562417d 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ configurations { repositories { mavenCentral() + maven { url 'https://repo.spring.io/milestone' } // Spring AI 저장소 추가 } dependencies { @@ -85,8 +86,7 @@ dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' //spring AI - implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter:1.0.0-SNAPSHOT' - + implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter:0.8.0' } clean { delete file('src/main/generated')} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e85b1a7..73fe8db 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -5,6 +5,9 @@ spring: name: Ripple profiles: active: ${SPRING_PROFILES_ACTIVE:local} # 기본 프로파일을 'local'로 설정 + ai: + openai: + api-key: ${OPENAI_API_KEY} #JWT jwt: From a37c434143c97728c7f5face5d5379cb5b65a51c Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Sat, 25 Jan 2025 17:28:30 +0900 Subject: [PATCH 03/13] =?UTF-8?q?Feat=20:=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=88=98=EC=A0=95=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ripple/BE/chatbot/domain/ChatMessage.java | 7 --- .../ripple/BE/chatbot/domain/ChatSession.java | 43 ------------------- .../java/com/ripple/BE/user/domain/User.java | 4 -- 3 files changed, 54 deletions(-) delete mode 100644 src/main/java/com/ripple/BE/chatbot/domain/ChatSession.java diff --git a/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java b/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java index d203ccd..b59f908 100644 --- a/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java +++ b/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java @@ -6,12 +6,9 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.Size; import lombok.AccessLevel; @@ -40,8 +37,4 @@ public class ChatMessage extends BaseEntity { @Enumerated(EnumType.STRING) @Column(name = "sender", nullable = false) private Sender sender; // 메시지 송신자 - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "chat_session_id") - private ChatSession chatSession; } diff --git a/src/main/java/com/ripple/BE/chatbot/domain/ChatSession.java b/src/main/java/com/ripple/BE/chatbot/domain/ChatSession.java deleted file mode 100644 index 7069c84..0000000 --- a/src/main/java/com/ripple/BE/chatbot/domain/ChatSession.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ripple.BE.chatbot.domain; - -import com.ripple.BE.global.entity.BaseEntity; -import com.ripple.BE.user.domain.User; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import java.util.ArrayList; -import java.util.List; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Table(name = "chat_sessions") -@Getter -@Builder -@Entity -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class ChatSession extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id", nullable = false) - private Long id; - - @OneToMany(mappedBy = "chatSession", cascade = CascadeType.ALL, orphanRemoval = true) - private List chatMessages = new ArrayList<>(); - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id") - private User user; // 챗봇 채팅 세션을 생성한 사용자 -} diff --git a/src/main/java/com/ripple/BE/user/domain/User.java b/src/main/java/com/ripple/BE/user/domain/User.java index 106434d..35f88ec 100644 --- a/src/main/java/com/ripple/BE/user/domain/User.java +++ b/src/main/java/com/ripple/BE/user/domain/User.java @@ -1,6 +1,5 @@ package com.ripple.BE.user.domain; -import com.ripple.BE.chatbot.domain.ChatSession; import com.ripple.BE.global.entity.BaseEntity; import com.ripple.BE.learning.domain.learningset.UserLearningSet; import com.ripple.BE.learning.domain.quiz.FailQuiz; @@ -128,9 +127,6 @@ public class User extends BaseEntity { @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List termScrapList = new ArrayList<>(); // 스크랩한 용어 목록 - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - private List chatSessionList = new ArrayList<>(); // 채팅 세션 목록 - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List userLearningSetList = new ArrayList<>(); // 학습 완료 목록 From 5cf6aa54116536bb9e2b88aab49336938eddd2d0 Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Sat, 25 Jan 2025 17:38:56 +0900 Subject: [PATCH 04/13] =?UTF-8?q?Feat=20:=20DTO=20=EC=83=9D=EC=84=B1=20(#2?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java | 11 +++++++++++ .../ripple/BE/chatbot/dto/request/ChatRequest.java | 6 ++++++ .../BE/chatbot/dto/response/ChatListResponse.java | 3 +++ .../ripple/BE/chatbot/dto/response/ChatResponse.java | 3 +++ 4 files changed, 23 insertions(+) create mode 100644 src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java create mode 100644 src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java create mode 100644 src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java create mode 100644 src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java diff --git a/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java b/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java new file mode 100644 index 0000000..94a234a --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java @@ -0,0 +1,11 @@ +package com.ripple.BE.chatbot.dto; + +import com.ripple.BE.chatbot.domain.ChatMessage; +import com.ripple.BE.chatbot.domain.type.Sender; + +public record ChatDTO(String message, Sender sender) { + + public static ChatDTO toChatDTO(final ChatMessage chatMessage) { + return new ChatDTO(chatMessage.getMessage(), chatMessage.getSender()); + } +} diff --git a/src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java b/src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java new file mode 100644 index 0000000..02d973c --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java @@ -0,0 +1,6 @@ +package com.ripple.BE.chatbot.dto.request; + +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.NotBlank; + +public record ChatRequest(@NotBlank @Max(1000) String message) {} diff --git a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java new file mode 100644 index 0000000..0a64d9e --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java @@ -0,0 +1,3 @@ +package com.ripple.BE.chatbot.dto.response; + +public record ChatListResponse() {} diff --git a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java new file mode 100644 index 0000000..c85d1e7 --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java @@ -0,0 +1,3 @@ +package com.ripple.BE.chatbot.dto.response; + +public record ChatResponse(String message) {} From fb004df2cae3c33157d930baba82f9e4abbc0994 Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Sat, 25 Jan 2025 17:43:02 +0900 Subject: [PATCH 05/13] =?UTF-8?q?Feat=20:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chatbot/controller/ChatbotController.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java diff --git a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java new file mode 100644 index 0000000..e0fd059 --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java @@ -0,0 +1,45 @@ +package com.ripple.BE.chatbot.controller; + +import com.ripple.BE.global.dto.response.ApiResponse; +import com.ripple.BE.user.domain.CustomUserDetails; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/api/v1/chatbot") +@Tag(name = "Chatbot", description = "챗봇 API") +public class ChatbotController { + + @Operation(summary = "챗봇에게 메세지 보내기", description = "챗봇에게 메세지를 보내고 응답을 받습니다. 대화 내용을 저장합니다.") + @PostMapping + public ResponseEntity> sendMessage( + final @AuthenticationPrincipal CustomUserDetails currentUser) { + + return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ApiResponse.EMPTY_RESPONSE)); + } + + @Operation(summary = "대화 내역 조회", description = "챗봇과의 대화 내역을 조회합니다.") + @GetMapping("/list") + public ResponseEntity> getMessages( + final @AuthenticationPrincipal CustomUserDetails currentUser) { + + return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ApiResponse.EMPTY_RESPONSE)); + } + + @Operation(summary = "대화 내역 초기화", description = "챗봇과의 대화 내역을 초기화합니다.") + @PostMapping("/clear") + public ResponseEntity> clearMessages( + final @AuthenticationPrincipal CustomUserDetails currentUser) { + + return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ApiResponse.EMPTY_RESPONSE)); + } +} From 3500b8b90768158e75341b7fa63046e95db2949a Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Mon, 27 Jan 2025 19:34:32 +0900 Subject: [PATCH 06/13] =?UTF-8?q?Feat=20:=20=EA=B7=B8=EB=9E=98=EB=93=A4=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 562417d..f0dc68e 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-devtools' //Lombok compileOnly 'org.projectlombok:lombok' From cc09ab6c18f98a7d1f1fa5e9636ddbdd2a1bd40f Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Mon, 27 Jan 2025 19:35:01 +0900 Subject: [PATCH 07/13] =?UTF-8?q?Feat=20:=20=EC=B1=97=EB=B4=87=20=EB=8C=80?= =?UTF-8?q?=ED=99=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=20=EC=99=84=EB=A3=8C=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chatbot/controller/ChatbotController.java | 15 +++++- .../ripple/BE/chatbot/domain/ChatMessage.java | 8 ++++ .../com/ripple/BE/chatbot/dto/ChatDTO.java | 5 ++ .../BE/chatbot/dto/request/ChatRequest.java | 3 +- .../chatbot/repository/ChatbotRepository.java | 6 +++ .../BE/chatbot/service/ChatbotService.java | 47 +++++++++++++++++++ 6 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java create mode 100644 src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java diff --git a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java index e0fd059..150773a 100644 --- a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java @@ -1,9 +1,14 @@ package com.ripple.BE.chatbot.controller; +import com.ripple.BE.chatbot.dto.ChatDTO; +import com.ripple.BE.chatbot.dto.request.ChatRequest; +import com.ripple.BE.chatbot.dto.response.ChatResponse; +import com.ripple.BE.chatbot.service.ChatbotService; import com.ripple.BE.global.dto.response.ApiResponse; import com.ripple.BE.user.domain.CustomUserDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -19,12 +24,18 @@ @Tag(name = "Chatbot", description = "챗봇 API") public class ChatbotController { + private final ChatbotService chatbotService; + @Operation(summary = "챗봇에게 메세지 보내기", description = "챗봇에게 메세지를 보내고 응답을 받습니다. 대화 내용을 저장합니다.") @PostMapping public ResponseEntity> sendMessage( - final @AuthenticationPrincipal CustomUserDetails currentUser) { + final @AuthenticationPrincipal CustomUserDetails currentUser, + final @Valid ChatRequest request) { - return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ApiResponse.EMPTY_RESPONSE)); + ChatResponse chatResponse = + chatbotService.sendMessage(ChatDTO.tochatDTO(request), currentUser.getId()); + + return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(chatResponse)); } @Operation(summary = "대화 내역 조회", description = "챗봇과의 대화 내역을 조회합니다.") diff --git a/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java b/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java index b59f908..71ca862 100644 --- a/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java +++ b/src/main/java/com/ripple/BE/chatbot/domain/ChatMessage.java @@ -2,13 +2,17 @@ import com.ripple.BE.chatbot.domain.type.Sender; import com.ripple.BE.global.entity.BaseEntity; +import com.ripple.BE.user.domain.User; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.Size; import lombok.AccessLevel; @@ -37,4 +41,8 @@ public class ChatMessage extends BaseEntity { @Enumerated(EnumType.STRING) @Column(name = "sender", nullable = false) private Sender sender; // 메시지 송신자 + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; // 작성자 } diff --git a/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java b/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java index 94a234a..916a1b2 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java @@ -2,10 +2,15 @@ import com.ripple.BE.chatbot.domain.ChatMessage; import com.ripple.BE.chatbot.domain.type.Sender; +import com.ripple.BE.chatbot.dto.request.ChatRequest; public record ChatDTO(String message, Sender sender) { public static ChatDTO toChatDTO(final ChatMessage chatMessage) { return new ChatDTO(chatMessage.getMessage(), chatMessage.getSender()); } + + public static ChatDTO tochatDTO(final ChatRequest request) { + return new ChatDTO(request.message(), Sender.USER); + } } diff --git a/src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java b/src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java index 02d973c..3e9ce3f 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/request/ChatRequest.java @@ -1,6 +1,5 @@ package com.ripple.BE.chatbot.dto.request; -import jakarta.validation.constraints.Max; import jakarta.validation.constraints.NotBlank; -public record ChatRequest(@NotBlank @Max(1000) String message) {} +public record ChatRequest(@NotBlank String message) {} diff --git a/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java new file mode 100644 index 0000000..821c893 --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java @@ -0,0 +1,6 @@ +package com.ripple.BE.chatbot.repository; + +import com.ripple.BE.chatbot.domain.ChatMessage; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChatbotRepository extends JpaRepository {} diff --git a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java new file mode 100644 index 0000000..72f790a --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java @@ -0,0 +1,47 @@ +package com.ripple.BE.chatbot.service; + +import com.ripple.BE.chatbot.domain.ChatMessage; +import com.ripple.BE.chatbot.domain.type.Sender; +import com.ripple.BE.chatbot.dto.ChatDTO; +import com.ripple.BE.chatbot.dto.response.ChatResponse; +import com.ripple.BE.chatbot.repository.ChatbotRepository; +import com.ripple.BE.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.openai.OpenAiChatClient; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Slf4j +@Transactional(readOnly = true) +public class ChatbotService { + private final OpenAiChatClient openAiChatClient; + + private final UserRepository userRepository; + private final ChatbotRepository chatbotRepository; + + @Transactional + public ChatResponse sendMessage(final ChatDTO chatDTO, final Long userId) { + String response = openAiChatClient.call(chatDTO.message()); + + // 유저의 메세지 저장 + chatbotRepository.save( + ChatMessage.builder() + .user(userRepository.findById(userId).get()) + .message(chatDTO.message()) + .sender(Sender.USER) + .build()); + + // 챗봇의 응답 저장 + chatbotRepository.save( + ChatMessage.builder() + .user(userRepository.findById(userId).get()) + .message(response) + .sender(Sender.CHATBOT) + .build()); + + return new ChatResponse(response); + } +} From f6a5cc5e84157800f4655c86f2c13762deb84815 Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Mon, 27 Jan 2025 19:35:12 +0900 Subject: [PATCH 08/13] =?UTF-8?q?Feat=20:=20yml=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-local.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 4cfd0e5..ca5fee2 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ spring: on-profile: local datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: ${DB_URL} - username: ${DB_USER} - password: ${DB_PASS} + url: ${LOCAL_DB_URL} + username: ${LOCAL_DB_USER} + password: ${LOCAL_DB_PASS} jpa: database: mysql database-platform: org.hibernate.dialect.MySQLDialect From 464d0c7bb673df276125f6ea083ef78b933b377e Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Mon, 27 Jan 2025 20:55:15 +0900 Subject: [PATCH 09/13] =?UTF-8?q?Feat=20:=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BE/chatbot/service/ChatbotService.java | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java index 72f790a..9a7b259 100644 --- a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java +++ b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java @@ -1,13 +1,19 @@ package com.ripple.BE.chatbot.service; +import static com.ripple.BE.user.exception.errorcode.UserErrorCode.*; + import com.ripple.BE.chatbot.domain.ChatMessage; import com.ripple.BE.chatbot.domain.type.Sender; import com.ripple.BE.chatbot.dto.ChatDTO; import com.ripple.BE.chatbot.dto.response.ChatResponse; import com.ripple.BE.chatbot.repository.ChatbotRepository; +import com.ripple.BE.user.domain.User; +import com.ripple.BE.user.exception.UserException; import com.ripple.BE.user.repository.UserRepository; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; + import org.springframework.ai.openai.OpenAiChatClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,23 +30,37 @@ public class ChatbotService { @Transactional public ChatResponse sendMessage(final ChatDTO chatDTO, final Long userId) { - String response = openAiChatClient.call(chatDTO.message()); + User user = userRepository.findById(userId) + .orElseThrow(() -> new UserException(USER_NOT_FOUND)); + + // 프롬프트 포함하여 OpenAI API 호출 + String prompt = """ + 당신은 경제학습 서비스를 위한 AI 챗봇입니다. + 오직 경제와 관련된 질문에만 답변해야 하며, 경제와 무관한 질문에는 답변하지 않습니다. + 모든 답변은 반드시 한국어로 제공해야 합니다. + 경제 이외의 주제에 대한 질문에는 다음과 같이 답변하세요: + "죄송합니다. 저는 경제 관련 질문에만 답변할 수 있습니다." + """; + + // OpenAI API 호출 + String response = openAiChatClient.call(prompt + "\n사용자 질문: " + chatDTO.message()); + // 유저 // 유저의 메세지 저장 chatbotRepository.save( - ChatMessage.builder() - .user(userRepository.findById(userId).get()) - .message(chatDTO.message()) - .sender(Sender.USER) - .build()); + ChatMessage.builder() + .user(user) + .message(chatDTO.message()) + .sender(Sender.USER) + .build()); // 챗봇의 응답 저장 chatbotRepository.save( - ChatMessage.builder() - .user(userRepository.findById(userId).get()) - .message(response) - .sender(Sender.CHATBOT) - .build()); + ChatMessage.builder() + .user(user) + .message(response) + .sender(Sender.CHATBOT) + .build()); return new ChatResponse(response); } From e07ce122a5f916a7f3b492bc41e28fc0d128e11e Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Mon, 27 Jan 2025 21:17:47 +0900 Subject: [PATCH 10/13] =?UTF-8?q?Feat=20:=20=EC=A1=B0=ED=9A=8C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chatbot/controller/ChatbotController.java | 11 +++++++-- .../ripple/BE/chatbot/dto/ChatListDTO.java | 24 +++++++++++++++++++ .../dto/response/ChatListResponse.java | 16 ++++++++++++- .../BE/chatbot/dto/response/ChatResponse.java | 13 +++++++++- .../chatbot/repository/ChatbotRepository.java | 7 +++++- .../BE/chatbot/service/ChatbotService.java | 19 ++++++++++++++- 6 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java diff --git a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java index 150773a..ecc01f6 100644 --- a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java @@ -1,7 +1,9 @@ package com.ripple.BE.chatbot.controller; import com.ripple.BE.chatbot.dto.ChatDTO; +import com.ripple.BE.chatbot.dto.ChatListDTO; import com.ripple.BE.chatbot.dto.request.ChatRequest; +import com.ripple.BE.chatbot.dto.response.ChatListResponse; import com.ripple.BE.chatbot.dto.response.ChatResponse; import com.ripple.BE.chatbot.service.ChatbotService; import com.ripple.BE.global.dto.response.ApiResponse; @@ -10,6 +12,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; + +import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -41,9 +45,12 @@ public ResponseEntity> sendMessage( @Operation(summary = "대화 내역 조회", description = "챗봇과의 대화 내역을 조회합니다.") @GetMapping("/list") public ResponseEntity> getMessages( - final @AuthenticationPrincipal CustomUserDetails currentUser) { + final @AuthenticationPrincipal CustomUserDetails currentUser, + final Pageable pageable) { - return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ApiResponse.EMPTY_RESPONSE)); + ChatListDTO chatList = chatbotService.getChatList(currentUser.getId(), pageable); + + return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ChatListResponse.toChatListResponse(chatList))); } @Operation(summary = "대화 내역 초기화", description = "챗봇과의 대화 내역을 초기화합니다.") diff --git a/src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java b/src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java new file mode 100644 index 0000000..1a38a47 --- /dev/null +++ b/src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java @@ -0,0 +1,24 @@ +package com.ripple.BE.chatbot.dto; + +import java.util.List; + +import org.springframework.data.domain.Page; + +import com.ripple.BE.chatbot.domain.ChatMessage; +import com.ripple.BE.post.domain.Post; +import com.ripple.BE.post.dto.PostDTO; +import com.ripple.BE.post.dto.PostListDTO; + +import lombok.Builder; + +@Builder +public record ChatListDTO ( + List chatDTOList, int totalPage, int currentPage +) { + public static ChatListDTO toChatListDTO(Page chatMessagePage) { + return new ChatListDTO( + chatMessagePage.getContent().stream().map(ChatDTO::toChatDTO).toList(), + chatMessagePage.getTotalPages(), + chatMessagePage.getNumber()); + } +} diff --git a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java index 0a64d9e..14c994f 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java @@ -1,3 +1,17 @@ package com.ripple.BE.chatbot.dto.response; -public record ChatListResponse() {} +import java.util.List; + +import com.ripple.BE.chatbot.domain.ChatMessage; +import com.ripple.BE.chatbot.dto.ChatDTO; +import com.ripple.BE.chatbot.dto.ChatListDTO; +import com.ripple.BE.post.dto.response.PostPreviewResponse; + +public record ChatListResponse(List postList, int totalPage, int currentPage) { + + public static ChatListResponse toChatListResponse(ChatListDTO chatListDTO) { + return new ChatListResponse( + chatListDTO.chatDTOList().stream().map(ChatResponse::toChatResponse).toList(), + chatListDTO.totalPage(), + chatListDTO.currentPage()); + } diff --git a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java index c85d1e7..e00aeeb 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java @@ -1,3 +1,14 @@ package com.ripple.BE.chatbot.dto.response; -public record ChatResponse(String message) {} +import com.ripple.BE.chatbot.domain.ChatMessage; +import com.ripple.BE.chatbot.dto.ChatDTO; + +public record ChatResponse( + String message, + String sender) { + + public static ChatResponse toChatResponse(ChatDTO chatDTO) { + return new ChatResponse(chatDTO.message(), chatDTO.sender().toString()); + } +} + diff --git a/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java index 821c893..7c8f3fd 100644 --- a/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java +++ b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java @@ -1,6 +1,11 @@ package com.ripple.BE.chatbot.repository; import com.ripple.BE.chatbot.domain.ChatMessage; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -public interface ChatbotRepository extends JpaRepository {} +public interface ChatbotRepository extends JpaRepository { + Page findAllByUserIdOrderByCreatedDate(Long userId, Pageable pageable); +} diff --git a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java index 9a7b259..86d6dc7 100644 --- a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java +++ b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java @@ -5,6 +5,8 @@ import com.ripple.BE.chatbot.domain.ChatMessage; import com.ripple.BE.chatbot.domain.type.Sender; import com.ripple.BE.chatbot.dto.ChatDTO; +import com.ripple.BE.chatbot.dto.ChatListDTO; +import com.ripple.BE.chatbot.dto.response.ChatListResponse; import com.ripple.BE.chatbot.dto.response.ChatResponse; import com.ripple.BE.chatbot.repository.ChatbotRepository; import com.ripple.BE.user.domain.User; @@ -15,6 +17,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.ai.openai.OpenAiChatClient; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -45,7 +49,6 @@ public ChatResponse sendMessage(final ChatDTO chatDTO, final Long userId) { // OpenAI API 호출 String response = openAiChatClient.call(prompt + "\n사용자 질문: " + chatDTO.message()); - // 유저 // 유저의 메세지 저장 chatbotRepository.save( ChatMessage.builder() @@ -64,4 +67,18 @@ public ChatResponse sendMessage(final ChatDTO chatDTO, final Long userId) { return new ChatResponse(response); } + + public ChatListDTO getChatList(final Long userId, final Pageable pageable) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new UserException(USER_NOT_FOUND)); + + Page page = chatbotRepository.findAllByUserIdOrderByCreatedDate( + user.getId(), pageable); + + return ChatListDTO.builder() + .chatDTOList(page.getContent().stream().map(ChatDTO::toChatDTO).toList()) + .currentPage(page.getNumber()) + .totalPage(page.getTotalPages()) + .build(); + } } From e112bd797d101476fb89df8662d6bdeaf4d7711f Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Mon, 27 Jan 2025 21:40:22 +0900 Subject: [PATCH 11/13] =?UTF-8?q?Feat=20:=20=EC=A1=B0=ED=9A=8C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=97=90=20=ED=8E=98=EC=9D=B4=EC=A7=95=EA=B3=BC=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chatbot/controller/ChatbotController.java | 15 ++++++---- .../com/ripple/BE/chatbot/dto/ChatDTO.java | 7 +++-- .../ripple/BE/chatbot/dto/ChatListDTO.java | 26 ++++++----------- .../dto/response/ChatListResponse.java | 19 +++++------- .../BE/chatbot/dto/response/ChatResponse.java | 19 +++++++----- .../chatbot/repository/ChatbotRepository.java | 1 - .../BE/chatbot/service/ChatbotService.java | 29 ++++++++++--------- 7 files changed, 57 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java index ecc01f6..5b636f2 100644 --- a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java @@ -11,15 +11,15 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; - -import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RequiredArgsConstructor @@ -42,15 +42,18 @@ public ResponseEntity> sendMessage( return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(chatResponse)); } - @Operation(summary = "대화 내역 조회", description = "챗봇과의 대화 내역을 조회합니다.") + @Operation( + summary = "대화 내역 조회", + description = "챗봇과의 대화 내역을 조회합니다. 페이지네이션을 지원합니다. 페이지당 10개의 대화 내역을 반환합니다.") @GetMapping("/list") public ResponseEntity> getMessages( final @AuthenticationPrincipal CustomUserDetails currentUser, - final Pageable pageable) { + final @RequestParam(defaultValue = "0") @PositiveOrZero int page) { - ChatListDTO chatList = chatbotService.getChatList(currentUser.getId(), pageable); + ChatListDTO chatList = chatbotService.getChatList(currentUser.getId(), page); - return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ChatListResponse.toChatListResponse(chatList))); + return ResponseEntity.status(HttpStatus.OK) + .body(ApiResponse.from(ChatListResponse.toChatListResponse(chatList))); } @Operation(summary = "대화 내역 초기화", description = "챗봇과의 대화 내역을 초기화합니다.") diff --git a/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java b/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java index 916a1b2..306fd1c 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/ChatDTO.java @@ -4,13 +4,14 @@ import com.ripple.BE.chatbot.domain.type.Sender; import com.ripple.BE.chatbot.dto.request.ChatRequest; -public record ChatDTO(String message, Sender sender) { +public record ChatDTO(String message, Sender sender, String createdAt) { public static ChatDTO toChatDTO(final ChatMessage chatMessage) { - return new ChatDTO(chatMessage.getMessage(), chatMessage.getSender()); + return new ChatDTO( + chatMessage.getMessage(), chatMessage.getSender(), chatMessage.getCreatedDate().toString()); } public static ChatDTO tochatDTO(final ChatRequest request) { - return new ChatDTO(request.message(), Sender.USER); + return new ChatDTO(request.message(), Sender.USER, null); } } diff --git a/src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java b/src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java index 1a38a47..17c8208 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/ChatListDTO.java @@ -1,24 +1,16 @@ package com.ripple.BE.chatbot.dto; -import java.util.List; - -import org.springframework.data.domain.Page; - import com.ripple.BE.chatbot.domain.ChatMessage; -import com.ripple.BE.post.domain.Post; -import com.ripple.BE.post.dto.PostDTO; -import com.ripple.BE.post.dto.PostListDTO; - +import java.util.List; import lombok.Builder; +import org.springframework.data.domain.Page; @Builder -public record ChatListDTO ( - List chatDTOList, int totalPage, int currentPage -) { - public static ChatListDTO toChatListDTO(Page chatMessagePage) { - return new ChatListDTO( - chatMessagePage.getContent().stream().map(ChatDTO::toChatDTO).toList(), - chatMessagePage.getTotalPages(), - chatMessagePage.getNumber()); - } +public record ChatListDTO(List chatDTOList, int totalPage, int currentPage) { + public static ChatListDTO toChatListDTO(Page chatMessagePage) { + return new ChatListDTO( + chatMessagePage.getContent().stream().map(ChatDTO::toChatDTO).toList(), + chatMessagePage.getTotalPages(), + chatMessagePage.getNumber()); + } } diff --git a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java index 14c994f..099ac68 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java @@ -1,17 +1,14 @@ package com.ripple.BE.chatbot.dto.response; -import java.util.List; - -import com.ripple.BE.chatbot.domain.ChatMessage; -import com.ripple.BE.chatbot.dto.ChatDTO; import com.ripple.BE.chatbot.dto.ChatListDTO; -import com.ripple.BE.post.dto.response.PostPreviewResponse; +import java.util.List; public record ChatListResponse(List postList, int totalPage, int currentPage) { - public static ChatListResponse toChatListResponse(ChatListDTO chatListDTO) { - return new ChatListResponse( - chatListDTO.chatDTOList().stream().map(ChatResponse::toChatResponse).toList(), - chatListDTO.totalPage(), - chatListDTO.currentPage()); - } + public static ChatListResponse toChatListResponse(ChatListDTO chatListDTO) { + return new ChatListResponse( + chatListDTO.chatDTOList().stream().map(ChatResponse::toChatResponse).toList(), + chatListDTO.totalPage(), + chatListDTO.currentPage()); + } +} diff --git a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java index e00aeeb..04f988b 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatResponse.java @@ -3,12 +3,17 @@ import com.ripple.BE.chatbot.domain.ChatMessage; import com.ripple.BE.chatbot.dto.ChatDTO; -public record ChatResponse( - String message, - String sender) { +public record ChatResponse(String message, String sender, String createdAt) { - public static ChatResponse toChatResponse(ChatDTO chatDTO) { - return new ChatResponse(chatDTO.message(), chatDTO.sender().toString()); - } -} + public static ChatResponse toChatResponse(ChatDTO chatDTO) { + return new ChatResponse( + chatDTO.message(), chatDTO.sender().toString(), chatDTO.createdAt().toString()); + } + public static ChatResponse toChatResponse(ChatMessage chatMessage) { + return new ChatResponse( + chatMessage.getMessage(), + chatMessage.getSender().toString(), + chatMessage.getCreatedDate().toString()); + } +} diff --git a/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java index 7c8f3fd..b4f6b72 100644 --- a/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java +++ b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java @@ -1,7 +1,6 @@ package com.ripple.BE.chatbot.repository; import com.ripple.BE.chatbot.domain.ChatMessage; - import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java index 86d6dc7..5cd9eb8 100644 --- a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java +++ b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java @@ -18,6 +18,7 @@ import org.springframework.ai.openai.OpenAiChatClient; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,6 +33,8 @@ public class ChatbotService { private final UserRepository userRepository; private final ChatbotRepository chatbotRepository; + private static final int PAGE_SIZE = 10; + @Transactional public ChatResponse sendMessage(final ChatDTO chatDTO, final Long userId) { User user = userRepository.findById(userId) @@ -58,27 +61,25 @@ public ChatResponse sendMessage(final ChatDTO chatDTO, final Long userId) { .build()); // 챗봇의 응답 저장 - chatbotRepository.save( - ChatMessage.builder() - .user(user) - .message(response) - .sender(Sender.CHATBOT) - .build()); + ChatMessage saved = chatbotRepository.save( + ChatMessage.builder() + .user(user) + .message(response) + .sender(Sender.CHATBOT) + .build()); - return new ChatResponse(response); + return ChatResponse.toChatResponse(saved); } - public ChatListDTO getChatList(final Long userId, final Pageable pageable) { + public ChatListDTO getChatList(final Long userId, final int page) { + Pageable pageable = PageRequest.of(page, PAGE_SIZE); + User user = userRepository.findById(userId) .orElseThrow(() -> new UserException(USER_NOT_FOUND)); - Page page = chatbotRepository.findAllByUserIdOrderByCreatedDate( + Page chatMessagePage = chatbotRepository.findAllByUserIdOrderByCreatedDate( user.getId(), pageable); - return ChatListDTO.builder() - .chatDTOList(page.getContent().stream().map(ChatDTO::toChatDTO).toList()) - .currentPage(page.getNumber()) - .totalPage(page.getTotalPages()) - .build(); + return ChatListDTO.toChatListDTO(chatMessagePage); } } From b58e8a44a6304b88b727b99dd980d16711239774 Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Mon, 27 Jan 2025 21:46:26 +0900 Subject: [PATCH 12/13] =?UTF-8?q?Feat=20:=20=EC=B4=88=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ripple/BE/chatbot/controller/ChatbotController.java | 2 ++ .../ripple/BE/chatbot/repository/ChatbotRepository.java | 2 ++ .../com/ripple/BE/chatbot/service/ChatbotService.java | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java index 5b636f2..ead92f2 100644 --- a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java @@ -61,6 +61,8 @@ public ResponseEntity> getMessages( public ResponseEntity> clearMessages( final @AuthenticationPrincipal CustomUserDetails currentUser) { + chatbotService.clearChat(currentUser.getId()); + return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(ApiResponse.EMPTY_RESPONSE)); } } diff --git a/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java index b4f6b72..987f7ba 100644 --- a/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java +++ b/src/main/java/com/ripple/BE/chatbot/repository/ChatbotRepository.java @@ -7,4 +7,6 @@ public interface ChatbotRepository extends JpaRepository { Page findAllByUserIdOrderByCreatedDate(Long userId, Pageable pageable); + + void deleteAllByUserId(Long userId); } diff --git a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java index 5cd9eb8..99009b2 100644 --- a/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java +++ b/src/main/java/com/ripple/BE/chatbot/service/ChatbotService.java @@ -82,4 +82,12 @@ public ChatListDTO getChatList(final Long userId, final int page) { return ChatListDTO.toChatListDTO(chatMessagePage); } + + @Transactional + public void clearChat(final Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new UserException(USER_NOT_FOUND)); + + chatbotRepository.deleteAllByUserId(user.getId()); + } } From 56b0e8ca25de227ddb874cf481c036583536cd8e Mon Sep 17 00:00:00 2001 From: chaen-ing Date: Tue, 28 Jan 2025 23:03:12 +0900 Subject: [PATCH 13/13] =?UTF-8?q?Debug=20:=20=EB=B3=80=EC=88=98=EB=AA=85?= =?UTF-8?q?=20=EB=93=B1=20=EC=88=98=EC=A0=95=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ripple/BE/chatbot/controller/ChatbotController.java | 3 ++- .../com/ripple/BE/chatbot/dto/response/ChatListResponse.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java index ead92f2..31d2c44 100644 --- a/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/ripple/BE/chatbot/controller/ChatbotController.java @@ -16,6 +16,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -57,7 +58,7 @@ public ResponseEntity> getMessages( } @Operation(summary = "대화 내역 초기화", description = "챗봇과의 대화 내역을 초기화합니다.") - @PostMapping("/clear") + @DeleteMapping("/clear") public ResponseEntity> clearMessages( final @AuthenticationPrincipal CustomUserDetails currentUser) { diff --git a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java index 099ac68..f19a432 100644 --- a/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java +++ b/src/main/java/com/ripple/BE/chatbot/dto/response/ChatListResponse.java @@ -3,7 +3,7 @@ import com.ripple.BE.chatbot.dto.ChatListDTO; import java.util.List; -public record ChatListResponse(List postList, int totalPage, int currentPage) { +public record ChatListResponse(List chatResponses, int totalPage, int currentPage) { public static ChatListResponse toChatListResponse(ChatListDTO chatListDTO) { return new ChatListResponse(