Skip to content

Commit

Permalink
Merge pull request #67 from 4ragrant/feature/#66-feature-chat-records…
Browse files Browse the repository at this point in the history
…-for-session

🔨 Feature: 채팅 기록 관련 세션 작업
  • Loading branch information
nar0ng authored Oct 27, 2024
2 parents f140410 + f63dace commit 7b48945
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package fouragrant.scentasy.biz.chat.controller;

import fouragrant.scentasy.biz.chat.domain.Chat;
import fouragrant.scentasy.biz.chat.dto.ChatListResDto;
import fouragrant.scentasy.biz.chat.dto.ChatReqDto;
import fouragrant.scentasy.biz.chat.dto.ChatResDto;
import fouragrant.scentasy.biz.chat.dto.ChatSessionListResDto;
import fouragrant.scentasy.biz.chat.service.ChatService;
import fouragrant.scentasy.biz.member.CustomUserDetails;
import fouragrant.scentasy.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
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 java.sql.Date;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -46,47 +46,62 @@ public class ChatController {
@Parameters({
@Parameter(name = "memberId", description = "멤버의 ID, path variable")
})
@PostMapping("/{memberId}")
@PostMapping("/{sessionId}")
public ResponseEntity<?> chat(@RequestBody ChatReqDto chatReqDto,
@PathVariable Long memberId) {
ChatResDto chatResDto = chatService.processChat(chatReqDto, memberId);
@AuthenticationPrincipal CustomUserDetails userDetails,
@PathVariable String sessionId) {
Long memberId = userDetails.getMemberId();
ChatResDto chatResDto = chatService.processChat(chatReqDto, memberId, sessionId);
return ResponseEntity.ok(Response.createSuccess("0000", chatResDto));
}

@Operation(summary = "멤버별 채팅 날짜 리스트 조회", description = "멤버별 채팅 내역이 있는 날짜 조회를 위한 메소드")
@ApiResponse(responseCode = "0000", description = "Successful retrieve chat dates",
@Operation(summary = "새로운 채팅 생성", description = "새로운 채팅 세션을 생성하는 메소드")
@ApiResponse(responseCode = "0000", description = "Successful new chat session creation",
content = @Content(
mediaType = "application/json"
)
)
@Parameters({
@Parameter(name = "memberId", description = "멤버의 ID, path variable")
})
@GetMapping("/dates/{memberId}")
public ResponseEntity<Response<List<Date>>> getChatDatesByMemberId(@PathVariable Long memberId) {
List<Date> chatDates = chatService.getChatDatesByMemberId(memberId);
return ResponseEntity.ok(Response.createSuccess("0000", chatDates));
@PostMapping("/new-session")
public ResponseEntity<Response<String>> createNewChatSession(@AuthenticationPrincipal CustomUserDetails userDetails) {
String sessionId = chatService.generateNewChatSessionId(userDetails.getMemberId());
return ResponseEntity.ok(Response.createSuccess("0000", sessionId));
}

@Operation(summary = "멤버별 날짜별 채팅 내역 조회", description = "멤버별 날짜별 채팅 내역 조회를 위한 메소드")
@ApiResponse(responseCode = "0000", description = "Successful retrieve chat lists",
@Operation(summary = "세션 ID로 채팅 기록 조회", description = "세션 ID를 통해 해당 채팅의 전체 기록을 조회하는 메소드")
@ApiResponse(responseCode = "0000", description = "Successful retrieve chat history by session ID",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ChatListResDto.class)
)
)
@Parameters({
@Parameter(name = "memberId", description = "멤버의 ID, path variable"),
@Parameter(name = "date", description = "날,, path variable")
@Parameter(name = "sessionId", description = "세션 ID, path variable")
})
@GetMapping("/{memberId}/{date}")
public ResponseEntity<Response<List<ChatListResDto>>> getChatsByMemberIdAndDate(@PathVariable Long memberId,
@PathVariable String date) {
LocalDate parsedDate = LocalDate.parse(date);
List<ChatListResDto> chats = chatService.getChatsByMemberIdAndDate(memberId, parsedDate);
@GetMapping("/sessions/{sessionId}")
public ResponseEntity<Response<List<ChatListResDto>>> getChatsBySessionId(
@PathVariable String sessionId,
@AuthenticationPrincipal CustomUserDetails userDetails) {
Long memberId = userDetails.getMemberId();

// 해당 멤버 ID와 세션 ID에 대한 채팅 기록을 조회
List<ChatListResDto> chats = chatService.getChatsBySessionIdAndMemberId(sessionId, memberId);
return ResponseEntity.ok(Response.createSuccess("0000", chats));
}

@Operation(summary = "멤버의 채팅 세션 ID 조회", description = "멤버의 채팅 기록이 있는 모든 세션 ID를 조회하는 메소드")
@ApiResponse(responseCode = "0000", description = "Successful retrieve chat sessions by member ID",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ChatSessionListResDto.class)
)
)
@GetMapping("/sessions")
public ResponseEntity<Response<List<ChatSessionListResDto>>> getChatSessionsByMemberId(
@AuthenticationPrincipal CustomUserDetails userDetails) {
Long memberId = userDetails.getMemberId();

List<ChatSessionListResDto> sessions = chatService.getChatSessionsByMemberId(memberId);
return ResponseEntity.ok(Response.createSuccess("0000", sessions));
}

}
5 changes: 3 additions & 2 deletions src/main/java/fouragrant/scentasy/biz/chat/domain/Chat.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public class Chat extends BaseTimeEntity {
/* -------------------------------------------- */
/* ------------ Information Column ------------ */
/* -------------------------------------------- */
@Column(nullable = false)
private String sessionId;

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

Expand All @@ -54,13 +57,11 @@ public class Chat extends BaseTimeEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;

/* -------------------------------------------- */
/* -------------- Relation Column ------------- */
/* -------------------------------------------- */
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
@JoinColumn(name = "member_id", nullable = false)
private Member member;

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
@Builder
public record ChatReqDto(
String input,
ExtraInfoReqDto extraInfo
) {

ExtraInfoReqDto extraInfo,
String sessionId) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fouragrant.scentasy.biz.chat.dto;

public record ChatResDto(
String response
String response,
String sessionId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package fouragrant.scentasy.biz.chat.dto;

import lombok.Builder;

@Builder
public record ChatSessionListResDto(
String sessionId
) {
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
package fouragrant.scentasy.biz.chat.repository;

import fouragrant.scentasy.biz.chat.domain.Chat;
import fouragrant.scentasy.biz.chat.dto.ChatListResDto;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface ChatRepository extends JpaRepository<Chat, Long> {
@Query("SELECT DISTINCT FUNCTION('DATE', c.createdAt) FROM chat c WHERE c.member.id = :memberId")
List<java.sql.Date> findDistinctChatDatesByMemberId(@Param("memberId") Long memberId);
List<Chat> findChatsBySessionIdAndMemberId(String sessionId, Long memberId);

@Query("SELECT c FROM chat c WHERE c.member.id = :memberId AND c.createdAt BETWEEN :startOfDay AND :endOfDay")
List<Chat> findChatsByMemberIdAndDate(@Param("memberId") Long memberId,
@Param("startOfDay") LocalDateTime startOfDay,
@Param("endOfDay") LocalDateTime endOfDay);
@Query("SELECT DISTINCT c.sessionId FROM chat c WHERE c.member.id = :memberId")
List<String> findDistinctSessionIdsByMemberId(Long memberId);

long countByMemberId(Long memberId);
}


41 changes: 23 additions & 18 deletions src/main/java/fouragrant/scentasy/biz/chat/service/ChatService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,15 @@
import fouragrant.scentasy.biz.chat.dto.ChatListResDto;
import fouragrant.scentasy.biz.chat.dto.ChatReqDto;
import fouragrant.scentasy.biz.chat.dto.ChatResDto;
import fouragrant.scentasy.biz.chat.dto.ChatSessionListResDto;
import fouragrant.scentasy.biz.chat.repository.ChatRepository;
import fouragrant.scentasy.biz.member.domain.ExtraInfo;
import fouragrant.scentasy.biz.member.domain.Member;
import fouragrant.scentasy.biz.member.dto.ExtraInfoReqDto;
import fouragrant.scentasy.biz.member.repository.MemberRepository;
import jakarta.transaction.Transactional;
import java.sql.Date;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -47,7 +43,7 @@ public ChatService(ChatRepository chatRepository, MemberRepository memberReposit
}

@Transactional
public ChatResDto processChat(ChatReqDto chatReqDto, Long memberId) {
public ChatResDto processChat(ChatReqDto chatReqDto, Long memberId, String sessionId) {
Member member = findMemberById(memberId);
ExtraInfo extraInfo = member.getExtraInfo();

Expand All @@ -58,20 +54,21 @@ public ChatResDto processChat(ChatReqDto chatReqDto, Long memberId) {
}

assert extraInfo != null;
ChatReqDto requestWithExtraInfo = new ChatReqDto(chatReqDto.input(), extraInfo.toDto());
ChatReqDto requestWithExtraInfo = new ChatReqDto(chatReqDto.input(), extraInfo.toDto(), sessionId);
log.info("{}", requestWithExtraInfo);
String response = communicateWithFlask(requestWithExtraInfo);

Chat chat = Chat.builder()
.input(chatReqDto.input())
.response(response)
.member(member)
.sessionId(sessionId)
.createdAt(LocalDateTime.now())
.build();

chatRepository.save(chat);

return new ChatResDto(response);
return new ChatResDto(response, sessionId);
}

private String communicateWithFlask(ChatReqDto chatReqDto) {
Expand Down Expand Up @@ -106,16 +103,9 @@ private Member findMemberById(Long memberId) {
.orElseThrow(() -> new IllegalArgumentException("Member not found with ID: " + memberId));
}

public List<Date> getChatDatesByMemberId(Long memberId) {
return chatRepository.findDistinctChatDatesByMemberId(memberId);
}

@Transactional
public List<ChatListResDto> getChatsByMemberIdAndDate(Long memberId, LocalDate date) {
LocalDateTime startOfDay = date.atStartOfDay();
LocalDateTime endOfDay = date.atTime(LocalTime.MAX);

return chatRepository.findChatsByMemberIdAndDate(memberId, startOfDay, endOfDay).stream()
public List<ChatListResDto> getChatsBySessionIdAndMemberId(String sessionId, Long memberId) {
return chatRepository.findChatsBySessionIdAndMemberId(sessionId, memberId).stream()
.map(chat -> ChatListResDto.builder()
.chatId(chat.getId())
.createdAt(chat.getCreatedAt())
Expand All @@ -125,6 +115,21 @@ public List<ChatListResDto> getChatsByMemberIdAndDate(Long memberId, LocalDate d
.collect(Collectors.toList());
}

@Transactional
public List<ChatSessionListResDto> getChatSessionsByMemberId(Long memberId) {
return chatRepository.findDistinctSessionIdsByMemberId(memberId).stream()
.map(sessionId -> ChatSessionListResDto.builder()
.sessionId(sessionId)
.build())
.collect(Collectors.toList());
}


@Transactional
public String generateNewChatSessionId(Long memberId) {
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new IllegalArgumentException("Member not found with ID: " + memberId));
String nickname = member.getExtraInfo().getNickname();
long nextId = chatRepository.countByMemberId(memberId) + 1;
return "chat_" + nextId + "_" + nickname;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ public class PerfumeController {
schema = @Schema(implementation = PerfumeRecipeResDto.class)
)
)
@PostMapping("/recipe")
public ResponseEntity<?> createRecipe(@AuthenticationPrincipal CustomUserDetails userDetails) {
@PostMapping("/recipe/{sessionId}")
public ResponseEntity<?> createRecipe(@AuthenticationPrincipal CustomUserDetails userDetails, String sessionId) {
Long memberId = userDetails.getMemberId();
PerfumeRecipeResDto perfumeRecipeResDto = perfumeRecipeService.processRecipe(memberId);

PerfumeRecipeResDto perfumeRecipeResDto = perfumeRecipeService.processRecipe(memberId, sessionId);
return ResponseEntity.ok(Response.createSuccess("0000", perfumeRecipeResDto));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public PerfumeRecipeService(PerfumeRepository perfumeRepository, MemberRepositor
}

@Transactional
public PerfumeRecipeResDto processRecipe(Long memberId) {
public PerfumeRecipeResDto processRecipe(Long memberId, String sessionId) {
Member member = findMemberById(memberId);

// Flask와 통신하여 JSON 응답을 받아옴
FlaskResponse responseData = communicateWithFlask();
FlaskResponse responseData = communicateWithFlask(sessionId);
String title = responseData.getTitle();
String description = responseData.getDescription();
String recipeArray = responseData.getPredictedNotes();
Expand Down Expand Up @@ -75,14 +75,14 @@ public PerfumeRecipeResDto processRecipe(Long memberId) {
return new PerfumeRecipeResDto(perfume.getPerfumeId(), perfume.getCreatedAt(), title, description, noteDescriptions, accords);
}

private FlaskResponse communicateWithFlask() {
private FlaskResponse communicateWithFlask(String sessionId) {
RestTemplate restTemplate = new RestTemplate();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

// 요청 본문 생성
PerfumeRecipeReqDto perfumeRecipeReqDto = new PerfumeRecipeReqDto("default_session");
PerfumeRecipeReqDto perfumeRecipeReqDto = new PerfumeRecipeReqDto(sessionId);
HttpEntity<PerfumeRecipeReqDto> entity = new HttpEntity<>(perfumeRecipeReqDto, headers);

try {
Expand Down Expand Up @@ -138,5 +138,4 @@ private List<Scent> mapRecipeArrayToNotes(String recipeArray) {

return notes;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import fouragrant.scentasy.biz.member.CustomUserDetails;
import fouragrant.scentasy.biz.member.domain.Member;
import fouragrant.scentasy.biz.member.service.MemberService;
import fouragrant.scentasy.biz.perfume.domain.Perfume;
import fouragrant.scentasy.biz.perfume.dto.PerfumeDto;
import fouragrant.scentasy.biz.perfume.repository.PerfumeRepository;
import fouragrant.scentasy.common.exception.CommonException;
import fouragrant.scentasy.common.exception.ErrorCode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.addServersItem(new Server().url("http://43.201.210.211:8080").description("Dev Server"))
.addServersItem(new Server().url("http://43.202.191.111:8080").description("Dev Server"))
.addServersItem(new Server().url("http://localhost:8080").description("Local Server"));
}
}
6 changes: 3 additions & 3 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ spring:

jpa:
hibernate:
ddl-auto: create-drop
# show-sql: true
ddl-auto: create
#show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MariaDBDialect

datasource:
url: ${DB_URL}
url: jdbc:mariadb://localhost:3306/scentasy
username: ${DB_USR}
password: ${DB_PASSWORD}
driver-class-name: org.mariadb.jdbc.Driver
Expand Down

0 comments on commit 7b48945

Please sign in to comment.