Skip to content
This repository has been archived by the owner on Oct 20, 2024. It is now read-only.

Commit

Permalink
[FEAT]: chatbot reaponse (#51)
Browse files Browse the repository at this point in the history
* [FEAT] #3 ChatGPT 응답

단답 확인 과정 테스트

* [FIX] #3 SecurityConfig permitAll 추가

* [FEAT] #3 ChatgptRequest 추가

GPT Request DTO format

* [FIX] #3 Chatgpt dependencies 추가

* [FEAT] #14 EduContent DTO 생성

* [FIX] #14 Post AccessLevel 수정

* [FEAT] #14 educontent 저장 api 구현

* [FEAT] #14 educontent 조회/상세조회/수정/삭제 api 구현

* [FEAT] #15 newscontent 저장/조회/상세조회/수정/삭제 api 구현

* [FEAT] #19 content 저장/조회/상세조회/수정/삭제 api 구현

* [FEAT] #19 swagger 설정 추가

* [FEAT] #19 readOnly를 위한 Transactional 어노테이션 추가

* [FEAT] #39 chatbot, comment 파일 추가

* fix: chat gpt 수정

* [FIX] #19 Transactional annotation readOnly default 수정

* Revert "[FIX] #19 Transactional annotation readOnly default 수정"

This reverts commit 4a18b0ebce60ff41bdacac044fd6c365adf49ca4.

* [FIX] #19 Transactional annotation readOnly default 수정

* [FEAT] #39 챗봇 질의응답 기능 개발

인사말 추가, 질의응답, 조회 기능

* [FEAT] educontent created_at 요청/응답 필드 추가

* [FIX] #39 챗봇 요청/응답값 UserId 부분 수정

* [FIX] #39 챗봇 요청/응답값 UserId 부분 수정

* [FIX] #39 swagger 코드 추가

---------

Co-authored-by: 박세진 <[email protected]>
  • Loading branch information
EunbeenDev and sejineer authored Jan 7, 2024
1 parent cae15c3 commit a918f98
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,23 @@ public class ChatGptService {

@Value("${chatgpt.api-key}")
private String apiKey;
// private final ObjectMapper objectMapper = new ObjectMapper()
// .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE );
// public Flux<String> ask(ChatgptQuestionRequest chatGptQuestionRequest) throws JsonProcessingException {
// WebClient client = WebClient.builder()
// .baseUrl(ChatgptConfig.CHAT_URL)
// .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
// .defaultHeader(ChatgptConfig.AUTHORIZATION, ChatgptConfig.BEARER + apiKey)
// .build();
//
// List<ChatGptMessage> messages = new ArrayList<>();
// messages.add(ChatGptMessage.builder()
// .role(ChatgptConfig.ROLE)
// .content(chatGptQuestionRequest.getQuestion())
// .build());
//
// ChatgptRequest chatGptRequest = new ChatgptRequest(
// ChatgptConfig.CHAT_MODEL,
// ChatgptConfig.MAX_TOKEN,
// ChatgptConfig.TEMPERATURE,
// ChatgptConfig.STREAM_TRUE,
// messages
// );
//
// String requestValue = objectMapper.writeValueAsString(chatGptRequest);
//
// Flux<String> eventStream = client.post()
// .bodyValue(requestValue)
// .accept(MediaType.TEXT_EVENT_STREAM)
// .retrieve()
// .bodyToFlux(String.class);
//
// return eventStream;
// }

// 단답 답변
public String getChatResponse(String prompt) {
System.out.print(apiKey);
// ChatGPT에 질문 전송
return chatgptService.sendMessage(prompt);
try{
String prompt_guide=
"너는 지금 청년들의 금융 지식을 향상시켜주기 위한 챗봇이야. 너의 이름은 '금토리'야. 너는 캐릭터의 역할이기 때문에 텍스트 형식으로 답변을 해야 해. 언어는 한국어로 말해야 하고, 말투는 친구한테 말하는 것처럼 반발로 해." +
"그리고 금융에 관련된 답변만 해야 하고, 만약 금융과 관련이 없는 질문이면 '미안해. 금융과 관련되지 않은 질문은 답변해줄 수 없어.'라고 말하면 돼. " +
"질문은 다음과 같아. 실제로 사용자와 대화하듯이 말해야 하고, 바로 질문에 대한 답을 해. 상식적으로 알 수도 있다는 말은 하지 마." +
"'네'라는 대답은 하지마. 인사말도 하지 마. 그리고 최대한 자세하게 답변해. 다시 한 번 말하지만, 반말로 말해. 그리고 문장은 끝까지 완전한 형태로 말 해";
prompt=prompt_guide.concat(prompt);
String response=chatgptService.sendMessage(prompt);
return response;
}
catch (Exception e){
e.printStackTrace();
return "request error";
}
}
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.finfellows.domain.chatgpt.presentation;

import com.finfellows.domain.chatgpt.application.ChatGptService;
import com.finfellows.domain.comment.application.CommentService;
import com.finfellows.domain.comment.domain.QComment;
import com.finfellows.global.config.security.token.CurrentUser;
import com.finfellows.global.config.security.token.UserPrincipal;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -14,24 +19,21 @@
@Slf4j
public class ChatGptController {
private final ChatGptService chatgptService;

// @PostMapping(value="/ask-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
// public Flux<String> ask(Locale locale,
// HttpServletRequest request,
// HttpServletResponse response,
// @RequestBody ChatgptQuestionRequest chatGptQuestionRequest){
// try {
// return chatgptService.ask(chatGptQuestionRequest);
// }catch (JsonProcessingException je){
// log.error(je.getMessage());
// return Flux.empty();
// }
// }
private final CommentService commentService;

// 단답 테스트
// https://yjkim-dev.tistory.com/56
@PostMapping("")
@PostMapping("/test")
public String test(@RequestBody String question) {
return chatgptService.getChatResponse(question);
}

// 답변 저장 테스트
@PostMapping("")
public String getChatResponse(@CurrentUser UserPrincipal userPrincipal, @RequestBody String question){
String answer= commentService.getChatResponse(question);
commentService.saveComment(userPrincipal.getId(), question, answer);
return answer;
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.finfellows.domain.comment.application;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.finfellows.domain.chatgpt.domain.ChatGptMessage;
Expand All @@ -9,7 +12,11 @@
import com.finfellows.domain.chatgpt.dto.request.ChatgptQuestionRequest;
import com.finfellows.domain.chatgpt.dto.request.ChatgptRequest;
import com.finfellows.domain.chatgpt.dto.response.ChatgptResponse;
import com.finfellows.domain.comment.domain.Comment;
import com.finfellows.domain.comment.domain.repository.CommentRepository;
import com.finfellows.domain.comment.dto.response.CommentResponse;
import com.finfellows.domain.user.domain.User;

import com.finfellows.domain.user.domain.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -20,6 +27,8 @@
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;


@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -81,4 +90,66 @@ public ChatgptResponse askQuestion(ChatgptQuestionRequest questionRequest) {
)
);
}


public String getChatResponse(String question){
String responseFromGPT=chatGptService.getChatResponse(question);
return responseFromGPT;
}

public void saveComment(Long userId, String question, String answer) {
Optional<User> optionalUser = userRepository.findById(userId);
User user = optionalUser.orElseThrow(() -> new RuntimeException("User not found"));

question = extractPromptFromJson(question);
answer = answer.replaceAll("\\n", "");
answer = answer.replaceAll("금토리: ", "");
answer = answer.replaceAll("네. ", "");

Comment comment = Comment.builder()
.question(question)
.answer(answer)
.user(user)
.build();
commentRepository.save(comment);
}

// JSON에서 "prompt" 부분 추출하는 메소드
private String extractPromptFromJson(String json) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(json);
if (jsonNode.has("prompt")) {
return jsonNode.get("prompt").asText();
}
} catch (JsonProcessingException e) {
System.out.print("텍스트 변환 실패");
}
return json;
}

public List<CommentResponse> getAllComments(Long userId) {
Optional<User> optionalUser = userRepository.findById(userId);
User user = optionalUser.orElseThrow(() -> new RuntimeException("User not found"));

List<Comment> comments = commentRepository.findAllByUserId(userId);

Comment greet = Comment.builder()
.greeting("안녕! 나는 금토리야. 도움이 필요하다면 편하게 말해줘.")
.user(user)
.build();
commentRepository.save(greet);

return comments.stream()
.map(comment -> CommentResponse.builder()
.commentId(comment.getCommentId())
.created_at(comment.getCreatedAt())
.greeting(comment.getGreeting())
.question(comment.getQuestion())
.answer(comment.getAnswer())
.userId(comment.getUser().getId())
.build()
)
.collect(Collectors.toList());
}
}
23 changes: 15 additions & 8 deletions src/main/java/com/finfellows/domain/comment/domain/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,30 @@
@Getter
public class Comment extends BaseEntity {

//질문 내용 저장 칼럼 필요함.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="comment_id", updatable = false, nullable = false, unique = true)
private Long commentId;

@Column(name="comment_content")
private String commentContent;
@Column(name = "greeting")
private String greeting;

@Column(name = "question")
private String question;

@Column(name="answer")
private String answer;

@ManyToOne
@JoinColumn(name="user_id")
private User userId;
private User user;

@Builder
public Comment(Long commentId, String commentContent, User userId){
this.commentId=commentId;
this.commentContent=commentContent;
this.userId=userId;
public Comment(String question, String greeting, String answer, User user){
this.greeting=greeting;
this.question=question;
this.answer=answer;
this.user=user;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

import com.finfellows.domain.comment.domain.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface CommentRepository extends JpaRepository<Comment, Long> {
List<Comment> findAllByUserId(Long userId);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.finfellows.domain.comment.dto.request;

import com.finfellows.domain.user.domain.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CommentRequest {
private Long commentId;
private LocalDateTime created_at;
private String greeting;
private String question;
private String answer;
private Long userId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.finfellows.domain.comment.dto.response;

import com.finfellows.domain.user.domain.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CommentResponse {
private Long commentId;
private LocalDateTime created_at;
private String greeting;
private String question;
private String answer;
private Long userId;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,61 @@
package com.finfellows.domain.comment.presentation;

import com.finfellows.domain.chatgpt.application.ChatGptService;
import com.finfellows.domain.comment.application.CommentService;
import com.finfellows.domain.comment.dto.response.CommentResponse;
import com.finfellows.domain.user.application.UserService;
import com.finfellows.global.config.security.token.CurrentUser;
import com.finfellows.global.config.security.token.UserPrincipal;
import io.swagger.v3.oas.annotations.Operation;
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.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/chatbot")
@Tag(name="Chatbot",description = "Chatbot API")
public class CommentController {
private CommentService commentService;
private ChatGptService chatGptService;
private UserService userService;


@Autowired
public CommentController(CommentService commentService, ChatGptService chatGptService, UserService userService) {
this.commentService = commentService;
this.chatGptService = chatGptService;
this.userService = userService;
}

@Operation(summary = "챗봇 질의응답 저장", description = "챗봇 질문과 답변을 저장합니다.")
@ApiResponse(responseCode = "200", description = "챗봇 질문에 대한 답변 응답 성공", content = {
@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = CommentResponse.class)))
})
@PostMapping("")
public String getChatResponse(@CurrentUser UserPrincipal userPrincipal, @RequestBody String question){
String answer= commentService.getChatResponse(question);
commentService.saveComment(userPrincipal.getId(), question, answer);
return answer;
}

@Operation(summary = "챗봇 대화 내용 조회", description = "챗봇 대화 전체 목록을 조회합니다.")
@ApiResponse(responseCode = "200", description = "챗봇 대화 목록 조회 성공", content = {
@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = CommentResponse.class)))
})
@GetMapping("")
public ResponseEntity<List<CommentResponse>> getAllComments(@CurrentUser UserPrincipal userPrincipal){
List<CommentResponse> responseList=commentService.getAllComments(userPrincipal.getId());
return new ResponseEntity<>(responseList, HttpStatus.OK);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
import lombok.Getter;
import lombok.NoArgsConstructor;


import java.time.LocalDateTime;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EduContentRequest {
private Long id;
private LocalDateTime created_at;
private String title;
private String content;
}
Loading

0 comments on commit a918f98

Please sign in to comment.