From 6339824fd1434bc3cfae88ba8f38df3178cbeb11 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 11:25:20 +0900 Subject: [PATCH 01/11] refactor: prompt edit --- src/main/resources/prompts/chatbot-response-rules.txt | 2 +- src/main/resources/prompts/chatbot-system-prompt.txt | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/resources/prompts/chatbot-response-rules.txt b/src/main/resources/prompts/chatbot-response-rules.txt index 4050b112..e1017859 100644 --- a/src/main/resources/prompts/chatbot-response-rules.txt +++ b/src/main/resources/prompts/chatbot-response-rules.txt @@ -1,4 +1,4 @@ -위의 시스템 프롬프트와 대화 기록을 참고하여, '쑤울 AI 바텐더'로서 친근하고 전문적인 답변을 제공해주세요. +위의 시스템 프롬프트와 대화 기록을 참고하여, 칵테일 AI 바텐더 '쑤리'로서 친근하고 전문적인 답변을 제공해주세요. 칵테일과 관련된 유용한 정보를 포함하되, 자연스럽고 대화하듯 응답해주세요. 【중요한 응답 규칙】 diff --git a/src/main/resources/prompts/chatbot-system-prompt.txt b/src/main/resources/prompts/chatbot-system-prompt.txt index 1b6b3a9a..ce212fd6 100644 --- a/src/main/resources/prompts/chatbot-system-prompt.txt +++ b/src/main/resources/prompts/chatbot-system-prompt.txt @@ -1,7 +1,7 @@ -당신은 'Ssoul' 칵테일 전문 AI 바텐더입니다. +당신은 'Ssoul' 칵테일 전문 AI 바텐더 '쑤리' 입니다. ## 역할과 페르소나 -- 이름: 쑤울 AI 바텐더 +- 이름: 쑤리 - 성격: 친근하고 전문적이며, 유머러스하면서도 신뢰할 수 있는 칵테일 전문가 - 말투: 반말이 아닌 존댓말을 사용하며, 친근한 바텐더처럼 대화 - 특징: 칵테일에 대한 깊은 지식과 함께 상황에 맞는 칵테일 추천 능력 @@ -21,8 +21,8 @@ 5. **창의성**: 클래식 칵테일 외에도 현대적 변형이나 논알콜 대안 제시 ## 응답 길이 제한 -- **기본 답변**: 200자 이내로 간결하게 작성 -- **레시피 제공**: 최대 300자 이내로 핵심만 전달 +- **기본 답변**: 300자 이내로 간결하게 작성 +- **레시피 제공**: 최대 400자 이내로 핵심만 전달 - **복잡한 설명**: 필요시 "더 알고 싶으시면 추가로 질문해주세요"로 마무리 - **한 문단**: 최대 3-4문장으로 제한 @@ -56,4 +56,5 @@ - 논알콜 칵테일(목테일)도 적극적으로 소개 - 홈바 입문자를 위한 기본 도구와 재료 안내 - 칵테일과 어울리는 안주나 분위기 추천 -- 과음 방지를 위한 적절한 조언 포함 \ No newline at end of file +- 과음 방지를 위한 적절한 조언 포함 +- 칵테일 추천에 대한 이유를 간단히 특징에 언급 \ No newline at end of file From 89cc984abf63b8b5a277366e5cf1a562ed8a7e50 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 12:12:51 +0900 Subject: [PATCH 02/11] feat: StepRecommendationRequestDto --- .../dto/StepRecommendationRequestDto.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java diff --git a/src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java b/src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java new file mode 100644 index 00000000..cc51477e --- /dev/null +++ b/src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java @@ -0,0 +1,20 @@ +package com.back.domain.chatbot.dto; + +import com.back.domain.cocktail.enums.AlcoholBaseType; +import com.back.domain.cocktail.enums.AlcoholStrength; +import com.back.domain.cocktail.enums.CocktailType; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class StepRecommendationRequestDto { + + private Long userId; + private AlcoholStrength alcoholStrength; // 1단계: 도수 + private AlcoholBaseType alcoholBaseType; // 2단계: 베이스 술 + private CocktailType cocktailType; // 3단계: 샷 잔 + private Integer step; // 현재 단계 (1: 도수, 2: 베이스술, 3: 샷잔, 4: 최종추천) +} \ No newline at end of file From e2fe280f03781cef501b4f4b86f0b84c00093cf4 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 12:13:44 +0900 Subject: [PATCH 03/11] feat: StepRecommendationResponseDto --- .../dto/StepRecommendationResponseDto.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/back/domain/chatbot/dto/StepRecommendationResponseDto.java diff --git a/src/main/java/com/back/domain/chatbot/dto/StepRecommendationResponseDto.java b/src/main/java/com/back/domain/chatbot/dto/StepRecommendationResponseDto.java new file mode 100644 index 00000000..08a8f41c --- /dev/null +++ b/src/main/java/com/back/domain/chatbot/dto/StepRecommendationResponseDto.java @@ -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 options; // 선택 옵션들 + private List 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; // 부가 설명 (선택사항) + } +} \ No newline at end of file From d10159cdb70d758e2bb7b3e72230eb647d59cfb3 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 12:18:40 +0900 Subject: [PATCH 04/11] feat: add Recommendation step on chatbotservice --- .../chatbot/service/ChatbotService.java | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java index f374c453..bc4c51b1 100644 --- a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java +++ b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java @@ -2,8 +2,16 @@ import com.back.domain.chatbot.dto.ChatRequestDto; import com.back.domain.chatbot.dto.ChatResponseDto; +import com.back.domain.chatbot.dto.StepRecommendationRequestDto; +import com.back.domain.chatbot.dto.StepRecommendationResponseDto; import com.back.domain.chatbot.entity.ChatConversation; import com.back.domain.chatbot.repository.ChatConversationRepository; +import com.back.domain.cocktail.dto.CocktailSummaryResponseDto; +import com.back.domain.cocktail.entity.Cocktail; +import com.back.domain.cocktail.enums.AlcoholBaseType; +import com.back.domain.cocktail.enums.AlcoholStrength; +import com.back.domain.cocktail.enums.CocktailType; +import com.back.domain.cocktail.repository.CocktailRepository; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -12,6 +20,8 @@ import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; +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; @@ -20,8 +30,10 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -30,6 +42,7 @@ public class ChatbotService { private final ChatModel chatModel; private final ChatConversationRepository chatConversationRepository; + private final CocktailRepository cocktailRepository; @Value("classpath:prompts/chatbot-system-prompt.txt") @@ -243,5 +256,119 @@ public List getUserChatHistory(Long userId) { return chatConversationRepository.findByUserIdOrderByCreatedAtDesc(userId, Pageable.unpaged()).getContent(); } + // 단계별 추천 로직 + public StepRecommendationResponseDto getStepRecommendation(StepRecommendationRequestDto requestDto) { + Integer currentStep = requestDto.getStep(); + + switch (currentStep) { + case 1: + return getAlcoholStrengthOptions(); + case 2: + return getAlcoholBaseTypeOptions(requestDto.getAlcoholStrength()); + case 3: + return getCocktailTypeOptions(requestDto.getAlcoholStrength(), requestDto.getAlcoholBaseType()); + case 4: + return getFinalRecommendations(requestDto); + default: + return getAlcoholStrengthOptions(); // 기본값은 첫 번째 단계 + } + } + + private StepRecommendationResponseDto getAlcoholStrengthOptions() { + List options = new ArrayList<>(); + + for (AlcoholStrength strength : AlcoholStrength.values()) { + options.add(new StepRecommendationResponseDto.StepOption( + strength.name(), + strength.getDescription(), + null + )); + } + + return new StepRecommendationResponseDto( + 1, + "원하시는 도수를 선택해주세요!", + options, + null, + false + ); + } + + private StepRecommendationResponseDto getAlcoholBaseTypeOptions(AlcoholStrength alcoholStrength) { + List options = new ArrayList<>(); + + for (AlcoholBaseType baseType : AlcoholBaseType.values()) { + options.add(new StepRecommendationResponseDto.StepOption( + baseType.name(), + baseType.getDescription(), + null + )); + } + + return new StepRecommendationResponseDto( + 2, + "베이스가 될 술을 선택해주세요!", + options, + null, + false + ); + } + + private StepRecommendationResponseDto getCocktailTypeOptions(AlcoholStrength alcoholStrength, AlcoholBaseType alcoholBaseType) { + List options = new ArrayList<>(); + + for (CocktailType cocktailType : CocktailType.values()) { + options.add(new StepRecommendationResponseDto.StepOption( + cocktailType.name(), + cocktailType.getDescription(), + null + )); + } + + return new StepRecommendationResponseDto( + 3, + "어떤 종류의 잔으로 드시겠어요?", + options, + null, + false + ); + } + + private StepRecommendationResponseDto getFinalRecommendations(StepRecommendationRequestDto requestDto) { + // 필터링 조건에 맞는 칵테일 검색 + List strengths = List.of(requestDto.getAlcoholStrength()); + List baseTypes = List.of(requestDto.getAlcoholBaseType()); + List cocktailTypes = List.of(requestDto.getCocktailType()); + + Page cocktailPage = cocktailRepository.searchWithFilters( + null, // 키워드 없음 + strengths, + cocktailTypes, + baseTypes, + PageRequest.of(0, 5) // 최대 5개 추천 + ); + + List recommendations = cocktailPage.getContent().stream() + .map(cocktail -> new CocktailSummaryResponseDto( + cocktail.getId(), + cocktail.getCocktailName(), + cocktail.getCocktailImgUrl(), + cocktail.getAlcoholStrength() + )) + .collect(Collectors.toList()); + + String stepTitle = recommendations.isEmpty() + ? "조건에 맞는 칵테일을 찾을 수 없습니다 😢" + : "당신을 위한 맞춤 칵테일 추천입니다! 🍹"; + + return new StepRecommendationResponseDto( + 4, + stepTitle, + null, + recommendations, + true + ); + } + } From bab1597f03ac77502bc82157d1fcf9c243c8e9ca Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 12:25:11 +0900 Subject: [PATCH 05/11] feat: new endpoint /step-recommendation --- .../chatbot/controller/ChatbotController.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java b/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java index b9e184d1..bb6a0734 100644 --- a/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java @@ -2,6 +2,8 @@ import com.back.domain.chatbot.dto.ChatRequestDto; import com.back.domain.chatbot.dto.ChatResponseDto; +import com.back.domain.chatbot.dto.StepRecommendationRequestDto; +import com.back.domain.chatbot.dto.StepRecommendationResponseDto; import com.back.domain.chatbot.entity.ChatConversation; import com.back.domain.chatbot.service.ChatbotService; import com.back.global.rsData.RsData; @@ -44,4 +46,16 @@ public ResponseEntity>> getUserChatHistory(@PathVa .body(RsData.failOf("서버 오류가 발생했습니다.")); } } + + @PostMapping("/step-recommendation") + public ResponseEntity> getStepRecommendation(@Valid @RequestBody StepRecommendationRequestDto requestDto) { + try { + StepRecommendationResponseDto response = chatbotService.getStepRecommendation(requestDto); + return ResponseEntity.ok(RsData.successOf(response)); + } catch (Exception e) { + log.error("단계별 추천 처리 중 오류 발생: ", e); + return ResponseEntity.internalServerError() + .body(RsData.failOf("서버 오류가 발생했습니다.")); + } + } } \ No newline at end of file From 91072a1d263a48c3ac94001bd80f6d78324ae1c4 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 12:26:57 +0900 Subject: [PATCH 06/11] feat: chatDto modified --- .../java/com/back/domain/chatbot/dto/ChatRequestDto.java | 4 +++- .../com/back/domain/chatbot/dto/ChatResponseDto.java | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java b/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java index 55fbe1f7..c6e3b215 100644 --- a/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java +++ b/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java @@ -13,6 +13,8 @@ public class ChatRequestDto { @NotBlank(message = "메시지는 필수입니다.") private String message; - private Long userId; + + // 단계별 추천 시작을 위한 필드 (선택사항) + private boolean startStepRecommendation = false; } \ No newline at end of file diff --git a/src/main/java/com/back/domain/chatbot/dto/ChatResponseDto.java b/src/main/java/com/back/domain/chatbot/dto/ChatResponseDto.java index 7b941e68..e96d1468 100644 --- a/src/main/java/com/back/domain/chatbot/dto/ChatResponseDto.java +++ b/src/main/java/com/back/domain/chatbot/dto/ChatResponseDto.java @@ -16,8 +16,17 @@ public class ChatResponseDto { private String response; private LocalDateTime timestamp; + // 단계별 추천 관련 필드 (선택사항) + private StepRecommendationResponseDto stepRecommendation; + public ChatResponseDto(String response) { this.response = response; this.timestamp = LocalDateTime.now(); } + + public ChatResponseDto(String response, StepRecommendationResponseDto stepRecommendation) { + this.response = response; + this.timestamp = LocalDateTime.now(); + this.stepRecommendation = stepRecommendation; + } } \ No newline at end of file From 8eda2b1c89c31ad8cd02735a1948b14bdf90bdb6 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 12:31:42 +0900 Subject: [PATCH 07/11] feat: service on keyword --- .../domain/chatbot/service/ChatbotService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java index bc4c51b1..b07fe68e 100644 --- a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java +++ b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java @@ -90,6 +90,14 @@ public void init() throws IOException { @Transactional public ChatResponseDto sendMessage(ChatRequestDto requestDto) { try { + // 단계별 추천 시작 요청인지 확인 + if (requestDto.isStartStepRecommendation() || isStepRecommendationTrigger(requestDto.getMessage())) { + StepRecommendationResponseDto stepRecommendation = getAlcoholStrengthOptions(); + String response = "단계별 맞춤 추천을 시작합니다! 🎯"; + saveConversation(requestDto, response); + return new ChatResponseDto(response, stepRecommendation); + } + // 메시지 타입 감지 MessageType messageType = detectMessageType(requestDto.getMessage()); @@ -251,6 +259,12 @@ private MessageType detectMessageType(String message) { return MessageType.CASUAL_CHAT; } + // 단계별 추천 시작 키워드 감지 + private boolean isStepRecommendationTrigger(String message) { + String lower = message.toLowerCase().trim(); + return lower.contains("단계별 추천"); + } + @Transactional(readOnly = true) public List getUserChatHistory(Long userId) { return chatConversationRepository.findByUserIdOrderByCreatedAtDesc(userId, Pageable.unpaged()).getContent(); From ccd3b7e338c3842a5850be570676ec0e330aa219 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 15:08:16 +0900 Subject: [PATCH 08/11] refactor: endpoint combination --- .../com/back/domain/chatbot/dto/ChatRequestDto.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java b/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java index c6e3b215..1c70af37 100644 --- a/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java +++ b/src/main/java/com/back/domain/chatbot/dto/ChatRequestDto.java @@ -1,5 +1,8 @@ package com.back.domain.chatbot.dto; +import com.back.domain.cocktail.enums.AlcoholBaseType; +import com.back.domain.cocktail.enums.AlcoholStrength; +import com.back.domain.cocktail.enums.CocktailType; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,6 +18,10 @@ public class ChatRequestDto { private Long userId; - // 단계별 추천 시작을 위한 필드 (선택사항) - private boolean startStepRecommendation = false; + // 단계별 추천 관련 필드들 + private boolean isStepRecommendation = false; + private Integer currentStep; + private AlcoholStrength selectedAlcoholStrength; + private AlcoholBaseType selectedAlcoholBaseType; + private CocktailType selectedCocktailType; } \ No newline at end of file From 0c99979e4590615b162d4a5a9450b41252f74656 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 15:23:38 +0900 Subject: [PATCH 09/11] refactor: del stepRecommendation endpoint, requestDto --- .../chatbot/controller/ChatbotController.java | 13 ---- .../dto/StepRecommendationRequestDto.java | 20 ------ .../chatbot/service/ChatbotService.java | 72 +++++++++++++------ 3 files changed, 49 insertions(+), 56 deletions(-) delete mode 100644 src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java diff --git a/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java b/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java index bb6a0734..495787c0 100644 --- a/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/back/domain/chatbot/controller/ChatbotController.java @@ -2,8 +2,6 @@ import com.back.domain.chatbot.dto.ChatRequestDto; import com.back.domain.chatbot.dto.ChatResponseDto; -import com.back.domain.chatbot.dto.StepRecommendationRequestDto; -import com.back.domain.chatbot.dto.StepRecommendationResponseDto; import com.back.domain.chatbot.entity.ChatConversation; import com.back.domain.chatbot.service.ChatbotService; import com.back.global.rsData.RsData; @@ -47,15 +45,4 @@ public ResponseEntity>> getUserChatHistory(@PathVa } } - @PostMapping("/step-recommendation") - public ResponseEntity> getStepRecommendation(@Valid @RequestBody StepRecommendationRequestDto requestDto) { - try { - StepRecommendationResponseDto response = chatbotService.getStepRecommendation(requestDto); - return ResponseEntity.ok(RsData.successOf(response)); - } catch (Exception e) { - log.error("단계별 추천 처리 중 오류 발생: ", e); - return ResponseEntity.internalServerError() - .body(RsData.failOf("서버 오류가 발생했습니다.")); - } - } } \ No newline at end of file diff --git a/src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java b/src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java deleted file mode 100644 index cc51477e..00000000 --- a/src/main/java/com/back/domain/chatbot/dto/StepRecommendationRequestDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.back.domain.chatbot.dto; - -import com.back.domain.cocktail.enums.AlcoholBaseType; -import com.back.domain.cocktail.enums.AlcoholStrength; -import com.back.domain.cocktail.enums.CocktailType; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -public class StepRecommendationRequestDto { - - private Long userId; - private AlcoholStrength alcoholStrength; // 1단계: 도수 - private AlcoholBaseType alcoholBaseType; // 2단계: 베이스 술 - private CocktailType cocktailType; // 3단계: 샷 잔 - private Integer step; // 현재 단계 (1: 도수, 2: 베이스술, 3: 샷잔, 4: 최종추천) -} \ No newline at end of file diff --git a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java index b07fe68e..88569a38 100644 --- a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java +++ b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java @@ -2,7 +2,6 @@ import com.back.domain.chatbot.dto.ChatRequestDto; import com.back.domain.chatbot.dto.ChatResponseDto; -import com.back.domain.chatbot.dto.StepRecommendationRequestDto; import com.back.domain.chatbot.dto.StepRecommendationResponseDto; import com.back.domain.chatbot.entity.ChatConversation; import com.back.domain.chatbot.repository.ChatConversationRepository; @@ -90,12 +89,9 @@ public void init() throws IOException { @Transactional public ChatResponseDto sendMessage(ChatRequestDto requestDto) { try { - // 단계별 추천 시작 요청인지 확인 - if (requestDto.isStartStepRecommendation() || isStepRecommendationTrigger(requestDto.getMessage())) { - StepRecommendationResponseDto stepRecommendation = getAlcoholStrengthOptions(); - String response = "단계별 맞춤 추천을 시작합니다! 🎯"; - saveConversation(requestDto, response); - return new ChatResponseDto(response, stepRecommendation); + // 단계별 추천 모드 확인 + if (requestDto.isStepRecommendation() || isStepRecommendationTrigger(requestDto.getMessage())) { + return handleStepRecommendation(requestDto); } // 메시지 타입 감지 @@ -265,29 +261,56 @@ private boolean isStepRecommendationTrigger(String message) { return lower.contains("단계별 추천"); } - @Transactional(readOnly = true) - public List getUserChatHistory(Long userId) { - return chatConversationRepository.findByUserIdOrderByCreatedAtDesc(userId, Pageable.unpaged()).getContent(); - } + // 단계별 추천 처리 통합 메서드 + private ChatResponseDto handleStepRecommendation(ChatRequestDto requestDto) { + Integer currentStep = requestDto.getCurrentStep(); - // 단계별 추천 로직 - public StepRecommendationResponseDto getStepRecommendation(StepRecommendationRequestDto requestDto) { - Integer currentStep = requestDto.getStep(); + // 단계가 지정되지 않았거나 첫 시작인 경우 + if (currentStep == null || currentStep <= 0) { + currentStep = 1; + } + + StepRecommendationResponseDto stepRecommendation; + String chatResponse; switch (currentStep) { case 1: - return getAlcoholStrengthOptions(); + stepRecommendation = getAlcoholStrengthOptions(); + chatResponse = "단계별 맞춤 추천을 시작합니다! 🎯\n원하시는 도수를 선택해주세요!"; + break; case 2: - return getAlcoholBaseTypeOptions(requestDto.getAlcoholStrength()); + stepRecommendation = getAlcoholBaseTypeOptions(requestDto.getSelectedAlcoholStrength()); + chatResponse = "좋은 선택이네요! 이제 베이스가 될 술을 선택해주세요 🍸"; + break; case 3: - return getCocktailTypeOptions(requestDto.getAlcoholStrength(), requestDto.getAlcoholBaseType()); + stepRecommendation = getCocktailTypeOptions(requestDto.getSelectedAlcoholStrength(), requestDto.getSelectedAlcoholBaseType()); + chatResponse = "완벽해요! 마지막으로 어떤 스타일로 즐기실 건가요? 🥃"; + break; case 4: - return getFinalRecommendations(requestDto); + stepRecommendation = getFinalRecommendations( + requestDto.getSelectedAlcoholStrength(), + requestDto.getSelectedAlcoholBaseType(), + requestDto.getSelectedCocktailType() + ); + chatResponse = stepRecommendation.getStepTitle(); + break; default: - return getAlcoholStrengthOptions(); // 기본값은 첫 번째 단계 + stepRecommendation = getAlcoholStrengthOptions(); + chatResponse = "단계별 맞춤 추천을 시작합니다! 🎯"; } + + // 대화 기록 저장 + saveConversation(requestDto, chatResponse); + + return new ChatResponseDto(chatResponse, stepRecommendation); } + @Transactional(readOnly = true) + public List getUserChatHistory(Long userId) { + return chatConversationRepository.findByUserIdOrderByCreatedAtDesc(userId, Pageable.unpaged()).getContent(); + } + + private StepRecommendationResponseDto getAlcoholStrengthOptions() { List options = new ArrayList<>(); @@ -348,11 +371,14 @@ private StepRecommendationResponseDto getCocktailTypeOptions(AlcoholStrength alc ); } - private StepRecommendationResponseDto getFinalRecommendations(StepRecommendationRequestDto requestDto) { + private StepRecommendationResponseDto getFinalRecommendations( + AlcoholStrength alcoholStrength, + AlcoholBaseType alcoholBaseType, + CocktailType cocktailType) { // 필터링 조건에 맞는 칵테일 검색 - List strengths = List.of(requestDto.getAlcoholStrength()); - List baseTypes = List.of(requestDto.getAlcoholBaseType()); - List cocktailTypes = List.of(requestDto.getCocktailType()); + List strengths = List.of(alcoholStrength); + List baseTypes = List.of(alcoholBaseType); + List cocktailTypes = List.of(cocktailType); Page cocktailPage = cocktailRepository.searchWithFilters( null, // 키워드 없음 From 295fd12a793a311567256b26686e6f0f4e9bdd43 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 16:41:35 +0900 Subject: [PATCH 10/11] fix: currentStep -> recommendation continue --- .../chatbot/service/ChatbotService.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java index 88569a38..8d80a250 100644 --- a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java +++ b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java @@ -89,11 +89,24 @@ public void init() throws IOException { @Transactional public ChatResponseDto sendMessage(ChatRequestDto requestDto) { try { - // 단계별 추천 모드 확인 - if (requestDto.isStepRecommendation() || isStepRecommendationTrigger(requestDto.getMessage())) { + // 디버깅용 로그 추가 + log.info("=== DEBUG INFO ==="); + log.info("isStepRecommendation: {}", requestDto.isStepRecommendation()); + log.info("currentStep: {}", requestDto.getCurrentStep()); + log.info("selectedAlcoholStrength: {}", requestDto.getSelectedAlcoholStrength()); + log.info("message: {}", requestDto.getMessage()); + log.info("=================="); + + // 단계별 추천 모드 확인 (currentStep이 있으면 무조건 단계별 추천 모드) + if (requestDto.isStepRecommendation() || + requestDto.getCurrentStep() != null || + isStepRecommendationTrigger(requestDto.getMessage())) { + log.info("단계별 추천 모드로 진입"); return handleStepRecommendation(requestDto); } + log.info("일반 채팅 모드로 진입"); + // 메시지 타입 감지 MessageType messageType = detectMessageType(requestDto.getMessage()); @@ -263,7 +276,9 @@ private boolean isStepRecommendationTrigger(String message) { // 단계별 추천 처리 통합 메서드 private ChatResponseDto handleStepRecommendation(ChatRequestDto requestDto) { + log.info("=== handleStepRecommendation 진입 ==="); Integer currentStep = requestDto.getCurrentStep(); + log.info("currentStep in handler: {}", currentStep); // 단계가 지정되지 않았거나 첫 시작인 경우 if (currentStep == null || currentStep <= 0) { From 3cafbed8669c22211b08dd15cf730de7faee2be0 Mon Sep 17 00:00:00 2001 From: GerHerMo Date: Fri, 26 Sep 2025 16:44:07 +0900 Subject: [PATCH 11/11] fix: delete useless debuging log --- .../domain/chatbot/service/ChatbotService.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java index 8d80a250..f0345115 100644 --- a/src/main/java/com/back/domain/chatbot/service/ChatbotService.java +++ b/src/main/java/com/back/domain/chatbot/service/ChatbotService.java @@ -89,23 +89,15 @@ public void init() throws IOException { @Transactional public ChatResponseDto sendMessage(ChatRequestDto requestDto) { try { - // 디버깅용 로그 추가 - log.info("=== DEBUG INFO ==="); - log.info("isStepRecommendation: {}", requestDto.isStepRecommendation()); - log.info("currentStep: {}", requestDto.getCurrentStep()); - log.info("selectedAlcoholStrength: {}", requestDto.getSelectedAlcoholStrength()); - log.info("message: {}", requestDto.getMessage()); - log.info("=================="); - // 단계별 추천 모드 확인 (currentStep이 있으면 무조건 단계별 추천 모드) if (requestDto.isStepRecommendation() || requestDto.getCurrentStep() != null || isStepRecommendationTrigger(requestDto.getMessage())) { - log.info("단계별 추천 모드로 진입"); + log.info("Recommendation chat mode for userId: {}", requestDto.getUserId()); return handleStepRecommendation(requestDto); } - log.info("일반 채팅 모드로 진입"); + log.info("Normal chat mode for userId: {}", requestDto.getUserId()); // 메시지 타입 감지 MessageType messageType = detectMessageType(requestDto.getMessage()); @@ -276,9 +268,7 @@ private boolean isStepRecommendationTrigger(String message) { // 단계별 추천 처리 통합 메서드 private ChatResponseDto handleStepRecommendation(ChatRequestDto requestDto) { - log.info("=== handleStepRecommendation 진입 ==="); Integer currentStep = requestDto.getCurrentStep(); - log.info("currentStep in handler: {}", currentStep); // 단계가 지정되지 않았거나 첫 시작인 경우 if (currentStep == null || currentStep <= 0) {