This repository has been archived by the owner on Oct 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Initial commit * Feat/#1 oauth2login (#3) * feat: User 엔터티 생성 * feat: jwt 버전 11->12, JWTUtil 생성 * feat: JWTFilter(JwtAuthenticationFilter) 등록 * feat: kakao 로그인 구현 * docs: swagger 태그(Authorization) 추가 (#5) * feat: User 엔터티 생성 * feat: jwt 버전 11->12, JWTUtil 생성 * feat: JWTFilter(JwtAuthenticationFilter) 등록 * feat: kakao 로그인 구현 * docs: swagger 태그(Authorization) 추가 * feat: accesstoken 테스트를 위한 test login 생성 (#9) * feat: User 엔티티에 상속 (#12) * feat: BaseEntity 생성 * feat: User 엔티티에 상속 * feat: 일기 생성 기능 구현 (#14) * feat: accesstoken 테스트를 위한 test login 생성 * feat: 일기 생성 기능 구현 * hotfix: ci 에러 수정 (#16) * feat: accesstoken 테스트를 위한 test login 생성 * feat: 일기 생성 기능 구현 * hotfix: ci 에러 수정 * fix: OIDC 카카오 로그인 nullPointerException 해결 * feat: 닉네임 설정 기능 구현 (#21) * feat: 일기 수정 기능 구현 (#25) * feat: 일기에 감정 컬럼 추가 * feat: 일기 수정 기능 구현 * feat: 일기 삭제 기능 구현 (#27) * feat: 일기에 감정 컬럼 추가 * feat: 일기 수정 기능 구현 * feat: 일기 삭제 기능 구현 * feat: 일기 감정 분석 기능 구현 (#31) * feat: 감정 저장 기능 구현 (#33) * feat: 일기 감정 분석 기능 구현 * feat: 감정 저장 기능 구현 * fix: 🐛 감정 저장 안되던 오류 수정 (#35) * feat: 일기 감정 분석 기능 구현 * feat: 감정 저장 기능 구현 * fix: 🐛 감정 저장 안되던 오류 수정 * hotfix: 🚑 서버 꺼짐 현상 해결 (#37) * feat: 일기 감정 분석 기능 구현 * feat: 감정 저장 기능 구현 * fix: 🐛 감정 저장 안되던 오류 수정 * hotfix: 🚑 서버 꺼짐 현상 해결 * feat: ✨ 홈 화면 조회 기능 구현 (#41) * feat: ✨ 회원가입 완료 여부 필드 추가 (#44) * feat: ✨ 일기 상세 조회 구현 (#47) * feat: ✨ 기간 별 감정 통계 조회 기능 구현 (#50) * feat: ✨ 일기 내용 검색 기능 구현 (#52) * feat: ✨ 감정 별 일기 조회 (#54) * feat: ✨ 월 별 일기 조회 기능 구현 (#59) * ci: ⚡ workflow 수정 (#61) * ci: ⚡ workflow 수정 * ci: ⚡ workflow 수정 * feat: ✨ user 엔터티 fcmToken 컬럼 추가, 로그인 시 토큰 최신화 구현 (#63) * ci: ⚡ workflow 수정 * ci: ⚡ workflow 수정 * feat: ✨ fcm 토큰 알림 기능 구현 * feat: ✨ user 엔터티 fcmToken 컬럼 추가, 로그인 시 토큰 최신화 구현 * feat: ✨ 북마크 추가/삭제 기능 구현, 일기/홈화면 조회 쿼리문 수정 (#65) * feat: ✨ 북마크 추가 기능 구현 * feat: ✨ 북마크 추가/삭제 기능 구현, 일기/홈화면 조회 쿼리문 수정 * feat: 🚀 fcmtoken 등록 api 분리 (#68) * feat: ✨ 유저 정보 조회 기능 구현 (#71) * Feat/#70 user info (#73) * feat: ✨ 유저 정보 조회 기능 구현 * hotfix: 🚑 cd 에러 해결 * refactor: 🚀 gpt prompt 수정 (#76) * feat: ✨ 일기 요약 스케줄러 구현 (#80) * refactor: 🚀 엔터티 접근 지정자 수정 (#84) * feat: ✨ 챗봇 임베딩 및 대화 기능 구현 완료 (#86)
- Loading branch information
1 parent
9b5d7b5
commit e8295f5
Showing
13 changed files
with
343 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/main/java/com/aidiary/domain/chatbot/application/ChatbotService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package com.aidiary.domain.chatbot.application; | ||
|
||
import com.aidiary.domain.chatbot.domain.ChatHistory; | ||
import com.aidiary.domain.chatbot.domain.ChatRole; | ||
import com.aidiary.domain.chatbot.domain.repository.ChatHistoryRepository; | ||
import com.aidiary.domain.chatbot.dto.DiaryEmbeddingReq; | ||
import com.aidiary.domain.chatbot.dto.QueryReq; | ||
import com.aidiary.domain.summary.domain.DiarySummary; | ||
import com.aidiary.domain.summary.domain.repository.DiarySummaryRepository; | ||
import com.aidiary.domain.user.domain.User; | ||
import com.aidiary.domain.user.domain.repository.UserRepository; | ||
import com.aidiary.global.config.security.token.UserPrincipal; | ||
import jakarta.persistence.EntityNotFoundException; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
@Slf4j | ||
public class ChatbotService { | ||
|
||
private final ChatHistoryRepository chatHistoryRepository; | ||
private final DiarySummaryRepository diarySummaryRepository; | ||
private final UserRepository userRepository; | ||
|
||
|
||
@Transactional | ||
public DiaryEmbeddingReq makeRequest(Long id) { | ||
User user = userRepository.findById(id) | ||
.orElseThrow(EntityNotFoundException::new); | ||
DiarySummary diarySummary = diarySummaryRepository.findByUser(user) | ||
.orElseThrow(EntityNotFoundException::new); | ||
|
||
DiaryEmbeddingReq diaryEmbeddingReq = DiaryEmbeddingReq.builder() | ||
.userId(id.toString()) | ||
.summarizedDiary(diarySummary.getSummarizedDiary()) | ||
.build(); | ||
|
||
return diaryEmbeddingReq; | ||
} | ||
|
||
@Transactional | ||
public QueryReq makeQuery(UserPrincipal userPrincipal, String question) { | ||
User user = userRepository.findById(userPrincipal.getId()) | ||
.orElseThrow(EntityNotFoundException::new); | ||
|
||
|
||
// 챗 히스토리를 최근 20개 이하로 가져온다 | ||
List<ChatHistory> recentChatHistoryByUserId = chatHistoryRepository.findRecentChatHistoryByUserId(userPrincipal.getId()); | ||
List<String> chatHistoryList = recentChatHistoryByUserId.stream() | ||
.map(chat -> String.format("%s: %s", chat.getChatRole() == ChatRole.USER ? "사용자" : "친구", chat.getMessage())) | ||
.toList(); | ||
|
||
log.info("User ID: {}", userPrincipal.getId()); | ||
log.info("Question: {}", question); | ||
log.info("Chat History: {}", chatHistoryList); | ||
|
||
ChatHistory chatHistory = ChatHistory.builder() | ||
.user(user) | ||
.message(question) | ||
.chatRole(ChatRole.USER) | ||
.build(); | ||
|
||
|
||
chatHistoryRepository.save(chatHistory); | ||
|
||
QueryReq queryReq = QueryReq.builder() | ||
.userId(userPrincipal.getId().toString()) | ||
.question(question) | ||
.chatHistory(chatHistoryList) | ||
.build(); | ||
|
||
return queryReq; | ||
|
||
} | ||
|
||
@Transactional | ||
public void registerBotChat(UserPrincipal userPrincipal, String result) { | ||
User user = userRepository.findById(userPrincipal.getId()) | ||
.orElseThrow(EntityNotFoundException::new); | ||
|
||
ChatHistory chatHistory = ChatHistory.builder() | ||
.user(user) | ||
.message(result) | ||
.chatRole(ChatRole.BOT) | ||
.build(); | ||
chatHistoryRepository.save(chatHistory); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
src/main/java/com/aidiary/domain/chatbot/domain/ChatHistory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.aidiary.domain.chatbot.domain; | ||
|
||
import com.aidiary.domain.common.BaseEntity; | ||
import com.aidiary.domain.user.domain.User; | ||
import jakarta.persistence.*; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class ChatHistory extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) | ||
@JoinColumn(name = "user_id") | ||
private User user; | ||
|
||
private String message; | ||
|
||
@Enumerated(EnumType.STRING) | ||
@Column(columnDefinition = "VARCHAR(10)") | ||
private ChatRole chatRole; | ||
|
||
|
||
@Builder | ||
public ChatHistory(User user, String message, ChatRole chatRole) { | ||
this.user = user; | ||
this.message = message; | ||
this.chatRole = chatRole; | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/com/aidiary/domain/chatbot/domain/ChatRole.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.aidiary.domain.chatbot.domain; | ||
|
||
public enum ChatRole { | ||
USER, | ||
BOT | ||
} |
9 changes: 9 additions & 0 deletions
9
...main/java/com/aidiary/domain/chatbot/domain/repository/ChatHistoryQueryDslRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.aidiary.domain.chatbot.domain.repository; | ||
|
||
import com.aidiary.domain.chatbot.domain.ChatHistory; | ||
|
||
import java.util.List; | ||
|
||
public interface ChatHistoryQueryDslRepository { | ||
List<ChatHistory> findRecentChatHistoryByUserId(Long id); | ||
} |
29 changes: 29 additions & 0 deletions
29
.../java/com/aidiary/domain/chatbot/domain/repository/ChatHistoryQueryDslRepositoryImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.aidiary.domain.chatbot.domain.repository; | ||
|
||
import com.aidiary.domain.chatbot.domain.ChatHistory; | ||
import com.aidiary.domain.chatbot.domain.QChatHistory; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.List; | ||
|
||
import static com.aidiary.domain.chatbot.domain.QChatHistory.chatHistory; | ||
|
||
@RequiredArgsConstructor | ||
@Repository | ||
public class ChatHistoryQueryDslRepositoryImpl implements ChatHistoryQueryDslRepository { | ||
|
||
private final JPAQueryFactory queryFactory; | ||
|
||
@Override | ||
public List<ChatHistory> findRecentChatHistoryByUserId(Long id) { | ||
return queryFactory | ||
.select(chatHistory) | ||
.from(chatHistory) | ||
.where(chatHistory.user.id.eq(id)) | ||
.orderBy(chatHistory.createdAt.desc()) | ||
.limit(20) | ||
.fetch(); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/aidiary/domain/chatbot/domain/repository/ChatHistoryRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.aidiary.domain.chatbot.domain.repository; | ||
|
||
import com.aidiary.domain.chatbot.domain.ChatHistory; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.List; | ||
|
||
public interface ChatHistoryRepository extends JpaRepository<ChatHistory, Long>, ChatHistoryQueryDslRepository { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.aidiary.domain.chatbot.dto; | ||
|
||
import lombok.Builder; | ||
|
||
@Builder | ||
public record ChatReq( | ||
String question | ||
) { | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/aidiary/domain/chatbot/dto/DiaryEmbeddingReq.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.aidiary.domain.chatbot.dto; | ||
|
||
import lombok.Builder; | ||
|
||
import java.util.List; | ||
|
||
@Builder | ||
public record DiaryEmbeddingReq( | ||
String userId, | ||
String summarizedDiary | ||
) { | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/com/aidiary/domain/chatbot/dto/QueryReq.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.aidiary.domain.chatbot.dto; | ||
|
||
import lombok.Builder; | ||
|
||
import java.util.List; | ||
|
||
@Builder | ||
public record QueryReq( | ||
String userId, | ||
String question, | ||
List<String> chatHistory | ||
) { | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/com/aidiary/domain/chatbot/dto/QueryRes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.aidiary.domain.chatbot.dto; | ||
|
||
import lombok.Builder; | ||
|
||
import java.util.List; | ||
|
||
@Builder | ||
public record QueryRes( | ||
String result | ||
) { | ||
} |
106 changes: 106 additions & 0 deletions
106
src/main/java/com/aidiary/domain/chatbot/presentation/ChatbotController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package com.aidiary.domain.chatbot.presentation; | ||
|
||
import com.aidiary.domain.chatbot.application.ChatbotService; | ||
import com.aidiary.domain.chatbot.dto.ChatReq; | ||
import com.aidiary.domain.chatbot.dto.DiaryEmbeddingReq; | ||
import com.aidiary.domain.chatbot.dto.QueryReq; | ||
import com.aidiary.global.config.security.token.CurrentUser; | ||
import com.aidiary.global.config.security.token.UserPrincipal; | ||
import com.aidiary.global.payload.ErrorResponse; | ||
import com.aidiary.global.payload.Message; | ||
import com.aidiary.global.payload.ResponseCustom; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
import io.swagger.v3.oas.annotations.media.ArraySchema; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.json.JSONObject; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.http.HttpEntity; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
@Tag(name = "Chatbot", description = "Chatbot API") | ||
@RequiredArgsConstructor | ||
@RestController | ||
@RequestMapping("/chatbot") | ||
@Slf4j | ||
public class ChatbotController { | ||
|
||
private final ChatbotService chatbotService; | ||
private final RestTemplate restTemplate = new RestTemplate(); | ||
|
||
@Value("${chatbot.fastApi.addDiaryUrl}") | ||
private String addDiaryUrl; | ||
|
||
@Value("${chatbot.fastApi.queryUrl}") | ||
private String queryUrl; | ||
|
||
|
||
@Operation(summary = "일기 임베딩", description = "유저의 일기를 AI 서버에 임베딩합니다.") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "일기 임베딩 성공", content = {@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = String.class)))}), | ||
@ApiResponse(responseCode = "400", description = "일기 임베딩 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}), | ||
}) | ||
@PostMapping("/embedding") | ||
public ResponseCustom<?> addEmbedding( | ||
@Parameter(description = "Accesstoken을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal | ||
) { | ||
String fastApiUrl = addDiaryUrl; | ||
|
||
HttpHeaders headers = new HttpHeaders(); | ||
headers.set("Content-Type", "application/json"); | ||
|
||
DiaryEmbeddingReq madeRequest = chatbotService.makeRequest(userPrincipal.getId()); | ||
|
||
HttpEntity<DiaryEmbeddingReq> requestEntity = new HttpEntity<>(madeRequest, headers); | ||
ResponseEntity<String> response = restTemplate.postForEntity(fastApiUrl, requestEntity, String.class); | ||
|
||
JSONObject responseBody = new JSONObject(response.getBody()); | ||
String message = responseBody.getString("message"); | ||
|
||
return ResponseCustom.OK(message); | ||
} | ||
|
||
@Operation(summary = "챗봇과 대화하기", description = "임베딩된 일기를 바탕으로 챗봇과 대화합니다.") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "챗봇 대화 성공", content = {@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = String.class)))}), | ||
@ApiResponse(responseCode = "400", description = "챗봇 대화 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}), | ||
}) | ||
@PostMapping("/chat") | ||
public ResponseCustom<?> chat( | ||
@Parameter(description = "Accesstoken을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal, | ||
@RequestBody ChatReq chatReq | ||
) { | ||
String fastApiUrl = queryUrl; | ||
|
||
HttpHeaders headers = new HttpHeaders(); | ||
headers.set("Content-Type", "application/json"); | ||
|
||
QueryReq queryReq = chatbotService.makeQuery(userPrincipal, chatReq.question()); | ||
|
||
log.info("Requesting FastAPI with QueryReq: {}", queryReq); | ||
|
||
HttpEntity<QueryReq> requestEntity = new HttpEntity<>(queryReq, headers); | ||
ResponseEntity<String> response = restTemplate.postForEntity(fastApiUrl, requestEntity, String.class); | ||
|
||
// JSON 응답에서 message 필드만 추출 | ||
JSONObject responseBody = new JSONObject(response.getBody()); | ||
String message = responseBody.getString("message"); | ||
|
||
// Bot 응답 저장 | ||
chatbotService.registerBotChat(userPrincipal, message); | ||
|
||
return ResponseCustom.OK(message); | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
src/main/java/com/aidiary/domain/summary/domain/repository/DiarySummaryRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
package com.aidiary.domain.summary.domain.repository; | ||
|
||
import com.aidiary.domain.summary.domain.DiarySummary; | ||
import com.aidiary.domain.user.domain.User; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface DiarySummaryRepository extends JpaRepository<DiarySummary, Long> { | ||
Optional<DiarySummary> findByUser(User user); | ||
} |