Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
274 changes: 179 additions & 95 deletions CHATBOT_GUIDE.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,7 @@ public class ChatContext {

@Schema(description = "대화 시작 시간 (타임스탬프)", example = "1693920000000")
private Long conversationStartTime;

@Schema(description = "사용자 언어", example = "ko", allowableValues = {"ko", "en", "ja", "zh"})
private String userLanguage;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ public class ChatRequest {

@Schema(description = "이전 대화에서 추출된 컨텍스트 정보")
private ChatContext context;

@Schema(description = "사용자 언어", example = "ko", allowableValues = {"ko", "en", "ja", "zh"})
@Builder.Default
private String language = "ko";
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Schema(description = "LLM 기반 의도 분류 결과")
@Getter
@Builder
@AllArgsConstructor
public class IntentClassificationResult {

@Schema(description = "분류된 의도", example = "CREATE_ROUTE")
Expand All @@ -32,6 +30,12 @@ public IntentClassificationResult(
this.reasoning = reasoning;
}

public IntentClassificationResult(UserIntent intent, double confidence, String reasoning) {
this.intent = intent;
this.confidence = confidence;
this.reasoning = reasoning;
}

public enum UserIntent {
CREATE_ROUTE("CREATE_ROUTE", "새로운 루트 생성/추천 요청"),
SEARCH_EXISTING_ROUTES("SEARCH_EXISTING_ROUTES", "기존에 만들어진 루트 검색 요청"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
public class ChatResponseBuilder {

private final ConversationManager conversationManager;
private final MessageTemplateService messageTemplateService;
private final LanguageService languageService;

/**
* 기본 질문 응답을 생성합니다.
Expand Down Expand Up @@ -64,9 +66,10 @@ public ChatResponse createQuestionResponse(String message, ChatContext context,
* 에러 응답을 생성합니다.
*/
public ChatResponse createErrorResponse(String message, ChatContext context) {
String language = context.getUserLanguage() != null ? context.getUserLanguage() : "ko";
return ChatResponse.builder()
.responseType(ChatResponse.ResponseType.QUESTION)
.message(message + " 다시 시도해주시겠어요?")
.message(message + " " + messageTemplateService.getErrorSuffix(language))
.context(context)
.build();
}
Expand All @@ -86,12 +89,13 @@ public ChatResponse createGeneralInfoResponse(String message, ChatContext contex
* 장소 정보 응답을 생성합니다.
*/
public ChatResponse createPlaceInfoResponse(String message, List<Place> places, ChatContext context) {
String language = context.getUserLanguage() != null ? context.getUserLanguage() : "ko";
List<ChatResponse.PlaceInfo> placeInfos = places.stream()
.map(place -> ChatResponse.PlaceInfo.builder()
.placeId(place.getPlaceId())
.name(place.getNameKo())
.description(place.getDescriptionKo())
.address(place.getAddressKo())
.name(languageService.getPlaceName(place, language))
.description(languageService.getPlaceDescription(place, language))
.address(languageService.getPlaceAddress(place, language))
.themes(place.getThemes())
.costInfo(place.getCostInfo())
.build())
Expand All @@ -111,9 +115,10 @@ public ChatResponse createPlaceInfoResponse(String message, List<Place> places,
public ChatResponse createExistingRoutesResponse(String message,
List<com.mey.backend.domain.route.entity.Route> routes,
ChatContext context) {
String language = context.getUserLanguage() != null ? context.getUserLanguage() : "ko";
List<ChatResponse.ExistingRoute> existingRoutes = routes.stream()
.limit(5) // 최대 5개 루트만 반환
.map(this::convertRouteToExistingRoute)
.map(route -> convertRouteToExistingRoute(route, language))
.toList();

return ChatResponse.builder()
Expand Down Expand Up @@ -163,16 +168,16 @@ public ChatResponse createAIRouteRecommendationResponse(String message,
/**
* Route 엔티티를 ExistingRoute DTO로 변환
*/
private ChatResponse.ExistingRoute convertRouteToExistingRoute(com.mey.backend.domain.route.entity.Route route) {
private ChatResponse.ExistingRoute convertRouteToExistingRoute(com.mey.backend.domain.route.entity.Route route, String language) {
// Theme enum을 String으로 변환
List<String> themeStrings = route.getThemes().stream()
.map(theme -> theme.getRouteTheme())
.toList();

return ChatResponse.ExistingRoute.builder()
.routeId(route.getId())
.title(route.getTitleKo())
.description(route.getDescriptionKo())
.title(languageService.getRouteTitle(route, language))
.description(languageService.getRouteDescription(route, language))
.estimatedCost(route.getTotalCost())
.durationMinutes(route.getTotalDurationMinutes())
.themes(themeStrings)
Expand All @@ -183,12 +188,7 @@ private ChatResponse.ExistingRoute convertRouteToExistingRoute(com.mey.backend.d
* 단계별 안내 메시지 생성
*/
public String generateStepMessage(ConversationState currentState, ChatContext context) {
return switch (currentState) {
case AWAITING_THEME -> "테마 선택이 필요해요. K-POP, K-드라마, K-푸드, K-패션 중 어떤 테마를 원하시나요?";
case AWAITING_REGION -> "좋습니다! " + (context.getTheme() != null ? context.getTheme().name() : "") + " 테마를 선택하셨네요. 어느 지역을 여행하고 싶으신가요?";
case AWAITING_DAYS -> (context.getRegion() != null ? context.getRegion() : "") + " 지역을 선택하셨네요! 몇 일 여행을 계획하고 계신가요?";
case READY_FOR_ROUTE -> "모든 정보가 준비되었습니다! 맞춤 루트를 생성해드릴게요.";
default -> "안내에 따라 정보를 입력해주세요.";
};
String language = context.getUserLanguage() != null ? context.getUserLanguage() : "ko";
return messageTemplateService.getStateMessage(currentState, language);
}
}
Loading