Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
6339824
refactor: prompt edit
GerHerMo Sep 26, 2025
89cc984
feat: StepRecommendationRequestDto
GerHerMo Sep 26, 2025
e2fe280
feat: StepRecommendationResponseDto
GerHerMo Sep 26, 2025
d10159c
feat: add Recommendation step on chatbotservice
GerHerMo Sep 26, 2025
bab1597
feat: new endpoint /step-recommendation
GerHerMo Sep 26, 2025
91072a1
feat: chatDto modified
GerHerMo Sep 26, 2025
8eda2b1
feat: service on keyword
GerHerMo Sep 26, 2025
ccd3b7e
refactor: endpoint combination
GerHerMo Sep 26, 2025
0c99979
refactor: del stepRecommendation endpoint, requestDto
GerHerMo Sep 26, 2025
295fd12
fix: currentStep -> recommendation continue
GerHerMo Sep 26, 2025
3cafbed
fix: delete useless debuging log
GerHerMo Sep 26, 2025
10ad8a2
Merge branch 'dev' into feat#154
GerHerMo Sep 26, 2025
7f1b105
Merge branch 'dev' into feat#154
GerHerMo Sep 29, 2025
83a961f
Merge branch 'dev' of https://github.com/prgrms-web-devcourse-final-p…
GerHerMo Sep 29, 2025
0c5ecb2
merge: 챗봇 단계별 추천 기능 추가
GerHerMo Sep 29, 2025
806b2a7
[refactor] MyBarController에서 사용자 인증 정보를 처리하는 방식을 리팩토링 #163 (#178)
MEOHIN Sep 30, 2025
d29952b
[chore] 불필요한 FQCN 사용을 제거하고 import 정리 #181 (#182)
MEOHIN Sep 30, 2025
89f5a66
refactor: non page, createdat modify
GerHerMo Sep 30, 2025
4d6994c
refactor: add Operation on Controller
GerHerMo Sep 30, 2025
83fe8f5
[test]Cocktail, CocktailComment controller testCase (#183)
lkw9241 Sep 30, 2025
6355371
[refactor] 컨트롤러에 @PreAuthorize 적용 및 인증 로직 제거 #184 (#186)
MEOHIN Sep 30, 2025
b7b2c69
refactor: MessageSender Enum
GerHerMo Sep 30, 2025
162475e
[feat]칵테일 1인 1댓글 제한 구현 (#189)
lkw9241 Sep 30, 2025
4428067
refactor: chatbotservice
GerHerMo Sep 30, 2025
d04561d
refactor: reop 5 -> 10
GerHerMo Sep 30, 2025
b0da4a3
feat: add two endpoint & Dto
GerHerMo Sep 30, 2025
72082cb
refactor: add logic on service
GerHerMo Sep 30, 2025
92d4319
refactor: 이미지 업로드 방식 변경에 대한 post 도메인 수정
seok6555 Sep 30, 2025
ff2a630
refactor: 이미지 업로드 방식 변경에 대한 post 도메인 수정
seok6555 Sep 30, 2025
dfdaa5d
[refactor] 이미지 업로드 방식 변경에 대한 post 도메인 수정#180
seok6555 Sep 30, 2025
085d1f7
[test] MyBarController 테스트 구현 #190 (#191)
MEOHIN Sep 30, 2025
d3ea62a
refactor: modi prompt on service
GerHerMo Sep 30, 2025
118a23a
refactor: serveral fix text
GerHerMo Sep 30, 2025
e1c1a8f
Merge branch 'dev' of https://github.com/prgrms-web-devcourse-final-p…
GerHerMo Sep 30, 2025
dc3f499
merge : 챗봇 엔티티 구조 수정 및 프롬포트 조정
GerHerMo Sep 30, 2025
e2bdf35
feat: enum - MessageType
GerHerMo Sep 30, 2025
3d8d0d4
test: Spring Security 통합 테스트 추가
seungwookc97 Sep 30, 2025
ed4f8d7
Merge branch 'dev' into test#179
seungwookc97 Sep 30, 2025
950a9dd
Merge pull request #200 from prgrms-web-devcourse-final-project/test#179
seungwookc97 Sep 30, 2025
31cb3ce
[feat] 커뮤니티 최신순, 인기순, 댓글순 정렬 구현
seok6555 Sep 30, 2025
b6e7b1d
feat: ChatResponseDto update
GerHerMo Sep 30, 2025
ceccc27
[test] MyHistoryController API 테스트 코드 작성 #192 (#202)
MEOHIN Sep 30, 2025
0fec988
feat: Service update
GerHerMo Sep 30, 2025
fc4facd
[feat] 커뮤니티 최신순, 인기순, 댓글순 정렬 구현#195
seok6555 Sep 30, 2025
4e9206f
feat: Service update v2 with Opus4.1
GerHerMo Sep 30, 2025
952c379
fix: isrecom~ add
GerHerMo Oct 1, 2025
bee84b1
[fix]DTO 수정 및 SQL 변경, CocktailShareController 리펙토링#203 (#205)
lkw9241 Oct 1, 2025
4d92a08
feat: greeting - change Dto
GerHerMo Oct 1, 2025
9205dc0
fix: greetingExists check for don't save duplicate greeting
GerHerMo Oct 1, 2025
6927d50
[feat] 조회수, 댓글수 카운트 기능 구현 & 카테고리 추가, 조회 구현
seok6555 Oct 1, 2025
3c483d6
[feat] 조회수, 댓글수 카운트 기능 구현 & 카테고리 추가, 조회 구현#206
seok6555 Oct 1, 2025
b30f7d3
[test] ProfileController 테스트 코드 추가 #204 (#209)
MEOHIN Oct 1, 2025
5130493
feat: options.add - ALL
GerHerMo Oct 1, 2025
c6e4e57
fix: MaxPage=3 on StepRecommendation
GerHerMo Oct 1, 2025
1b8a3e4
Merge branch 'dev' of https://github.com/prgrms-web-devcourse-final-p…
GerHerMo Oct 1, 2025
ea857a1
merge : 단계별 추천 추가 및 '전체' 옵션 추가
GerHerMo Oct 1, 2025
e8f2e0f
fix: all option parsing logic add
GerHerMo Oct 1, 2025
cd22572
[merge] 전체 옵션 오류 해결 #212
GerHerMo Oct 1, 2025
67fee64
[feat] 게시글 정렬 기능과 카테고리 기능을 같이 사용할 수 있도록 구현
seok6555 Oct 1, 2025
01893ab
[feat] 프로필 상단 카드 요약에 '킵한 칵테일 수' 집계 구현 #210 (#217)
MEOHIN Oct 1, 2025
2c227e4
[feat] 게시글 정렬 기능과 카테고리 기능을 같이 사용할 수 있도록 구현#208
seok6555 Oct 1, 2025
2e3c3c3
[test] NotificationController의 알림 관련 기능 통합 테스트 추가 #218 (#220)
MEOHIN Oct 1, 2025
8a67f5f
[Refactor#216 (#221)
lkw9241 Oct 2, 2025
2cdd242
chore: CICD test
seungwookc97 Oct 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dependencies {

// AWS S3
implementation("io.awspring.cloud:spring-cloud-aws-starter-s3:3.4.0")
implementation("com.amazonaws:aws-java-sdk-s3:1.12.777")

runtimeOnly("com.h2database:h2")
runtimeOnly("com.mysql:mysql-connector-j")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import com.back.domain.chatbot.dto.ChatRequestDto;
import com.back.domain.chatbot.dto.ChatResponseDto;
import com.back.domain.chatbot.dto.SaveBotMessageDto;
import com.back.domain.chatbot.entity.ChatConversation;
import com.back.domain.chatbot.service.ChatbotService;
import com.back.global.rsData.RsData;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -22,6 +24,7 @@ public class ChatbotController {
private final ChatbotService chatbotService;

@PostMapping("/chat")
@Operation(summary = "채팅 메시지 보내기", description = "자율형 대화 및 단계별 추천 두가지 모드 지원")
public ResponseEntity<RsData<ChatResponseDto>> sendMessage(@Valid @RequestBody ChatRequestDto requestDto) {
try {
ChatResponseDto response = chatbotService.sendMessage(requestDto);
Expand All @@ -34,6 +37,7 @@ public ResponseEntity<RsData<ChatResponseDto>> sendMessage(@Valid @RequestBody C
}

@GetMapping("/history/user/{userId}")
@Operation(summary = "유저 대화 히스토리", description = "사용자 채팅 기록 조회")
public ResponseEntity<RsData<List<ChatConversation>>> getUserChatHistory(@PathVariable Long userId) {
try {
List<ChatConversation> history = chatbotService.getUserChatHistory(userId);
Expand All @@ -44,4 +48,31 @@ public ResponseEntity<RsData<List<ChatConversation>>> getUserChatHistory(@PathVa
.body(RsData.failOf("서버 오류가 발생했습니다."));
}
}

@PostMapping("/bot-message")
@Operation(summary = "봇 메시지 저장", description = "FE에서 생성한 봇 메시지(인사말 등)를 DB에 저장")
public ResponseEntity<RsData<ChatConversation>> saveBotMessage(@Valid @RequestBody SaveBotMessageDto requestDto) {
try {
ChatConversation savedMessage = chatbotService.saveBotMessage(requestDto);
return ResponseEntity.ok(RsData.successOf(savedMessage));
} catch (Exception e) {
log.error("봇 메시지 저장 중 오류 발생: ", e);
return ResponseEntity.internalServerError()
.body(RsData.failOf("서버 오류가 발생했습니다."));
}
}

@PostMapping("/greeting/{userId}")
@Operation(summary = "인사말 생성", description = "사용자가 채팅을 시작할 때 기본 인사말을 생성하고 저장")
public ResponseEntity<RsData<ChatResponseDto>> createGreeting(@PathVariable Long userId) {
try {
ChatResponseDto greeting = chatbotService.createGreetingMessage(userId);
return ResponseEntity.ok(RsData.successOf(greeting));
} catch (Exception e) {
log.error("인사말 생성 중 오류 발생: ", e);
return ResponseEntity.internalServerError()
.body(RsData.failOf("서버 오류가 발생했습니다."));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ public class ChatRequestDto {
@NotBlank(message = "메시지는 필수입니다.")
private String message;


private Long userId;

// 단계별 추천 관련 필드들
private boolean isStepRecommendation = false;
private Integer currentStep;
private String selectedAlcoholStrength; // "ALL" 처리를 위해 스텝 3개 String으로 변경
private String selectedAlcoholBaseType;
private String selectedCocktailType;
}
51 changes: 48 additions & 3 deletions src/main/java/com/back/domain/chatbot/dto/ChatResponseDto.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.back.domain.chatbot.dto;

import com.back.domain.chatbot.enums.MessageType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
Expand All @@ -11,13 +13,56 @@
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ChatResponseDto {

private String response;
private String message; // 텍스트 메시지
private MessageType type; // 메시지 표시 타입
private LocalDateTime timestamp;

public ChatResponseDto(String response) {
this.response = response;
// 단계별 추천 관련 데이터 (type이 RADIO_OPTIONS 또는 CARD_LIST일 때 사용)
private StepRecommendationResponseDto stepData;

// 추가 메타데이터
private MetaData metaData;

// 생성자들
public ChatResponseDto(String message) {
this.message = message;
this.type = MessageType.TEXT;
this.timestamp = LocalDateTime.now();
}

public ChatResponseDto(String message, StepRecommendationResponseDto stepData) {
this.message = message;
this.timestamp = LocalDateTime.now();
this.stepData = stepData;

// stepData 내용에 따라 type 자동 설정
if (stepData != null) {
if (stepData.getOptions() != null && !stepData.getOptions().isEmpty()) {
this.type = MessageType.RADIO_OPTIONS;
} else if (stepData.getRecommendations() != null && !stepData.getRecommendations().isEmpty()) {
this.type = MessageType.CARD_LIST;
} else {
this.type = MessageType.TEXT;
}
} else {
this.type = MessageType.TEXT;
}
}

// 메타데이터 내부 클래스
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class MetaData {
private Integer currentStep; // 현재 단계 (단계별 추천)
private Integer totalSteps; // 전체 단계 수
private Boolean isTyping; // 타이핑 애니메이션 표시 여부
private Integer delay; // 메시지 표시 지연 시간(ms)
private String actionType; // 버튼 액션 타입
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/back/domain/chatbot/dto/SaveBotMessageDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

package com.back.domain.chatbot.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SaveBotMessageDto {

@NotNull(message = "사용자 ID는 필수입니다.")
private Long userId;

@NotBlank(message = "메시지 내용은 필수입니다.")
private String message;

// 선택적: 메시지 타입 (GREETING, HELP, ERROR 등)
private String messageType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.back.domain.chatbot.dto;

import com.back.domain.cocktail.dto.CocktailSummaryResponseDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class StepRecommendationResponseDto {

private Integer currentStep; // 현재 단계
private String stepTitle; // 단계 제목 (예: "원하시는 도수를 선택해주세요!")
private List<StepOption> options; // 선택 옵션들
private List<CocktailSummaryResponseDto> recommendations; // 최종 추천 칵테일 (4단계에서만)
private boolean isCompleted; // 추천이 완료되었는지 여부

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class StepOption {
private String value; // enum 값 (예: "NON_ALCOHOLIC")
private String label; // 화면에 표시될 텍스트 (예: "논알콜 (0%)")
private String description; // 부가 설명 (선택사항)
}
}
19 changes: 10 additions & 9 deletions src/main/java/com/back/domain/chatbot/entity/ChatConversation.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.back.domain.chatbot.entity;

import com.back.domain.chatbot.enums.MessageSender;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;

import java.time.LocalDateTime;

Expand All @@ -19,18 +21,17 @@ public class ChatConversation {
@GeneratedValue(strategy = IDENTITY)
private Long id;

@Column(nullable = false)
private Long userId;

@Column(columnDefinition = "TEXT")
private String userMessage;
@Column(columnDefinition = "TEXT", nullable = false)
private String message;

@Column(columnDefinition = "TEXT")
private String botResponse;
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 20)
@Builder.Default
private MessageSender sender = MessageSender.USER;

@CreatedDate
private LocalDateTime createdAt;

@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/back/domain/chatbot/enums/MessageSender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.back.domain.chatbot.enums;

public enum MessageSender {
USER("사용자"),
CHATBOT("챗봇");

private final String description;

MessageSender(String description) {
this.description = description;
}

public String getDescription() {
return description;
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/back/domain/chatbot/enums/MessageType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.back.domain.chatbot.enums;

public enum MessageType {
TEXT("텍스트"), // 일반 텍스트 메시지
RADIO_OPTIONS("라디오옵션"), // 라디오 버튼 선택지
CARD_LIST("카드리스트"), // 칵테일 추천 카드 리스트
LOADING("로딩중"), // 로딩 메시지
ERROR("에러"); // 에러 메시지

private final String description;

MessageType(String description) {
this.description = description;
}

public String getDescription() {
return description;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.back.domain.chatbot.repository;

import com.back.domain.chatbot.entity.ChatConversation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

Expand All @@ -11,7 +9,9 @@
@Repository
public interface ChatConversationRepository extends JpaRepository<ChatConversation, Long> {

Page<ChatConversation> findByUserIdOrderByCreatedAtDesc(Long userId, Pageable pageable);
List<ChatConversation> findByUserIdOrderByCreatedAtDesc(Long userId);

List<ChatConversation> findTop5ByUserIdOrderByCreatedAtDesc(Long userId);
List<ChatConversation> findTop20ByUserIdOrderByCreatedAtDesc(Long userId);

boolean existsByUserIdAndMessage(Long userId, String message);
}
Loading