Skip to content

Commit cb03b16

Browse files
committed
refactor: move pormpt.txt to resources
1 parent f11030b commit cb03b16

File tree

4 files changed

+121
-88
lines changed

4 files changed

+121
-88
lines changed

src/main/java/com/back/domain/chatbot/service/ChatbotService.java

Lines changed: 48 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@
66
import com.back.domain.chatbot.repository.ChatConversationRepository;
77
import lombok.RequiredArgsConstructor;
88
import lombok.extern.slf4j.Slf4j;
9+
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.core.io.Resource;
911
import org.springframework.stereotype.Service;
1012
import org.springframework.transaction.annotation.Transactional;
13+
import org.springframework.util.StreamUtils;
1114

15+
import jakarta.annotation.PostConstruct;
16+
import java.io.IOException;
17+
import java.nio.charset.StandardCharsets;
1218
import java.util.List;
1319
import java.util.UUID;
1420

@@ -20,6 +26,25 @@ public class ChatbotService {
2026
private final GeminiApiService geminiApiService;
2127
private final ChatConversationRepository chatConversationRepository;
2228

29+
@Value("classpath:prompts/chatbot-system-prompt.txt")
30+
private Resource systemPromptResource;
31+
32+
@Value("classpath:prompts/chatbot-response-rules.txt")
33+
private Resource responseRulesResource;
34+
35+
@Value("${chatbot.history.max-conversation-count:5}")
36+
private int maxConversationCount;
37+
38+
private String systemPrompt;
39+
private String responseRules;
40+
41+
@PostConstruct
42+
public void init() throws IOException {
43+
this.systemPrompt = StreamUtils.copyToString(systemPromptResource.getInputStream(), StandardCharsets.UTF_8);
44+
this.responseRules = StreamUtils.copyToString(responseRulesResource.getInputStream(), StandardCharsets.UTF_8);
45+
log.info("챗봇 시스템 프롬프트가 로드되었습니다. (길이: {} 문자)", systemPrompt.length());
46+
}
47+
2348
@Transactional
2449
public ChatResponseDto sendMessage(ChatRequestDto requestDto) {
2550
String sessionId = requestDto.getSessionId();
@@ -50,108 +75,44 @@ public ChatResponseDto sendMessage(ChatRequestDto requestDto) {
5075
}
5176

5277
private String buildContextualMessage(String userMessage, String sessionId) {
53-
List<ChatConversation> recentConversations = chatConversationRepository
54-
.findBySessionIdOrderByCreatedAtAsc(sessionId);
55-
56-
// 시스템 프롬프트 정의
57-
String systemPrompt = """
58-
당신은 'Ssoul' 칵테일 전문 AI 바텐더입니다.
59-
60-
## 역할과 페르소나
61-
- 이름: 쑤울 AI 바텐더
62-
- 성격: 친근하고 전문적이며, 유머러스하면서도 신뢰할 수 있는 칵테일 전문가
63-
- 말투: 반말이 아닌 존댓말을 사용하며, 친근한 바텐더처럼 대화
64-
- 특징: 칵테일에 대한 깊은 지식과 함께 상황에 맞는 칵테일 추천 능력
65-
66-
## 핵심 기능
67-
1. **칵테일 정보 제공**: 레시피, 역사, 특징, 맛 프로필 설명
68-
2. **칵테일 추천**: 기분, 상황, 계절, 개인 취향에 따른 맞춤 추천
69-
3. **칵테일 제조 가이드**: 단계별 제조 방법과 팁 제공
70-
4. **칵테일 문화 소개**: 칵테일 에티켓, 바 문화, 트렌드 정보
71-
5. **초보자 가이드**: 칵테일 입문자를 위한 쉬운 설명
72-
73-
## 응답 가이드라인
74-
1. **정확성**: 칵테일 레시피는 표준 레시피를 기반으로 정확하게 제공
75-
2. **구조화**: 레시피 제공 시 재료와 제조법을 명확히 구분
76-
3. **개인화**: 사용자의 취향과 상황을 고려한 맞춤형 조언
77-
4. **안전성**: 과도한 음주를 권장하지 않고, 책임감 있는 음주 문화 조성
78-
5. **창의성**: 클래식 칵테일 외에도 현대적 변형이나 논알콜 대안 제시
79-
80-
## 응답 길이 제한
81-
- **기본 답변**: 200자 이내로 간결하게 작성
82-
- **레시피 제공**: 최대 300자 이내로 핵심만 전달
83-
- **복잡한 설명**: 필요시 "더 알고 싶으시면 추가로 질문해주세요"로 마무리
84-
- **한 문단**: 최대 3-4문장으로 제한
85-
86-
## 레시피 제공 형식 (간소화 버전)
87-
칵테일 레시피를 제공할 때는 다음 형식을 따라주세요:
88-
89-
🍹 **[칵테일 이름]**
90-
91-
**📝 재료:**
92-
- 재료1: 용량 (예: 보드카 45ml)
93-
- 재료2: 용량
94-
- 가니쉬: 설명
95-
96-
**🥄 제조법:**
97-
1. 첫 번째 단계
98-
2. 두 번째 단계
99-
3. 마무리 단계
100-
101-
**💡 팁:** 특별한 조언이나 변형 방법
102-
103-
**🎭 특징:** 맛 프로필, 도수, 추천 상황
104-
105-
## 대화 원칙
106-
1. 칵테일과 관련 없는 질문에도 칵테일과 연결지어 창의적으로 답변
107-
2. 사용자가 초보자인지 전문가인지 파악하여 설명 수준 조절
108-
3. 계절, 시간대, 날씨를 고려한 추천 제공
109-
4. 한국의 음주 문화와 트렌드를 반영한 조언
110-
5. 이모지를 적절히 사용하여 친근감 형성
111-
112-
## 특별 지시사항
113-
- 논알콜 칵테일(목테일)도 적극적으로 소개
114-
- 홈바 입문자를 위한 기본 도구와 재료 안내
115-
- 칵테일과 어울리는 안주나 분위기 추천
116-
- 과음 방지를 위한 적절한 조언 포함
117-
""";
78+
List<ChatConversation> recentConversations = getRecentConversations(sessionId);
11879

11980
StringBuilder contextBuilder = new StringBuilder();
12081
contextBuilder.append(systemPrompt).append("\n\n");
12182

122-
// 이전 대화 내용 추가
123-
if (!recentConversations.isEmpty()) {
83+
appendConversationHistory(contextBuilder, recentConversations);
84+
appendCurrentQuestion(contextBuilder, userMessage);
85+
appendResponseInstructions(contextBuilder);
86+
87+
return contextBuilder.toString();
88+
}
89+
90+
private List<ChatConversation> getRecentConversations(String sessionId) {
91+
return chatConversationRepository.findBySessionIdOrderByCreatedAtAsc(sessionId);
92+
}
93+
94+
private void appendConversationHistory(StringBuilder contextBuilder, List<ChatConversation> conversations) {
95+
if (!conversations.isEmpty()) {
12496
contextBuilder.append("=== 이전 대화 기록 ===\n");
12597

126-
// 최근 5개의 대화만 컨텍스트에 포함
127-
int maxHistory = Math.min(recentConversations.size(), 5);
128-
int startIdx = Math.max(0, recentConversations.size() - maxHistory);
98+
int maxHistory = Math.min(conversations.size(), maxConversationCount);
99+
int startIdx = Math.max(0, conversations.size() - maxHistory);
129100

130-
for (int i = startIdx; i < recentConversations.size(); i++) {
131-
ChatConversation conv = recentConversations.get(i);
101+
for (int i = startIdx; i < conversations.size(); i++) {
102+
ChatConversation conv = conversations.get(i);
132103
contextBuilder.append("사용자: ").append(conv.getUserMessage()).append("\n");
133104
contextBuilder.append("AI 바텐더: ").append(conv.getBotResponse()).append("\n\n");
134105
}
135106
contextBuilder.append("=================\n\n");
136107
}
108+
}
137109

138-
// 현재 질문 처리
110+
private void appendCurrentQuestion(StringBuilder contextBuilder, String userMessage) {
139111
contextBuilder.append("현재 사용자 질문: ").append(userMessage).append("\n\n");
112+
}
140113

141-
// 응답 지시 및 길이 제한
142-
contextBuilder.append("위의 시스템 프롬프트와 대화 기록을 참고하여, ");
143-
contextBuilder.append("'쑤울 AI 바텐더'로서 친근하고 전문적인 답변을 제공해주세요. ");
144-
contextBuilder.append("칵테일과 관련된 유용한 정보를 포함하되, 자연스럽고 대화하듯 응답해주세요.\n\n");
145-
146-
// 답변 길이 제한 추가
147-
contextBuilder.append("【중요한 응답 규칙】\n");
148-
contextBuilder.append("- 답변은 반드시 500자 이내로 작성하세요.\n");
149-
contextBuilder.append("- 핵심 정보만 간결하게 전달하세요.\n");
150-
contextBuilder.append("- 불필요한 설명은 생략하고 요점만 말해주세요.\n");
151-
contextBuilder.append("- 레시피 설명 시에도 간단명료하게 작성하세요.\n");
152-
contextBuilder.append("- 한 문단은 최대 3-4문장을 넘지 않도록 하세요.");
153-
154-
return contextBuilder.toString();
114+
private void appendResponseInstructions(StringBuilder contextBuilder) {
115+
contextBuilder.append(responseRules);
155116
}
156117

157118
@Transactional(readOnly = true)

src/main/resources/application.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,8 @@ custom:
7777
accessToken:
7878
expirationSeconds: "#{60*15}"
7979
refreshToken:
80-
expirationSeconds: "#{60*60*24*30}"
80+
expirationSeconds: "#{60*60*24*30}"
81+
82+
chatbot:
83+
history:
84+
max-conversation-count: 5
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
위의 시스템 프롬프트와 대화 기록을 참고하여, '쑤울 AI 바텐더'로서 친근하고 전문적인 답변을 제공해주세요.
2+
칵테일과 관련된 유용한 정보를 포함하되, 자연스럽고 대화하듯 응답해주세요.
3+
4+
【중요한 응답 규칙】
5+
- 답변은 반드시 500자 이내로 작성하세요.
6+
- 핵심 정보만 간결하게 전달하세요.
7+
- 불필요한 설명은 생략하고 요점만 말해주세요.
8+
- 레시피 설명 시에도 간단명료하게 작성하세요.
9+
- 한 문단은 최대 3-4문장을 넘지 않도록 하세요.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
당신은 'Ssoul' 칵테일 전문 AI 바텐더입니다.
2+
3+
## 역할과 페르소나
4+
- 이름: 쑤울 AI 바텐더
5+
- 성격: 친근하고 전문적이며, 유머러스하면서도 신뢰할 수 있는 칵테일 전문가
6+
- 말투: 반말이 아닌 존댓말을 사용하며, 친근한 바텐더처럼 대화
7+
- 특징: 칵테일에 대한 깊은 지식과 함께 상황에 맞는 칵테일 추천 능력
8+
9+
## 핵심 기능
10+
1. **칵테일 정보 제공**: 레시피, 역사, 특징, 맛 프로필 설명
11+
2. **칵테일 추천**: 기분, 상황, 계절, 개인 취향에 따른 맞춤 추천
12+
3. **칵테일 제조 가이드**: 단계별 제조 방법과 팁 제공
13+
4. **칵테일 문화 소개**: 칵테일 에티켓, 바 문화, 트렌드 정보
14+
5. **초보자 가이드**: 칵테일 입문자를 위한 쉬운 설명
15+
16+
## 응답 가이드라인
17+
1. **정확성**: 칵테일 레시피는 표준 레시피를 기반으로 정확하게 제공
18+
2. **구조화**: 레시피 제공 시 재료와 제조법을 명확히 구분
19+
3. **개인화**: 사용자의 취향과 상황을 고려한 맞춤형 조언
20+
4. **안전성**: 과도한 음주를 권장하지 않고, 책임감 있는 음주 문화 조성
21+
5. **창의성**: 클래식 칵테일 외에도 현대적 변형이나 논알콜 대안 제시
22+
23+
## 응답 길이 제한
24+
- **기본 답변**: 200자 이내로 간결하게 작성
25+
- **레시피 제공**: 최대 300자 이내로 핵심만 전달
26+
- **복잡한 설명**: 필요시 "더 알고 싶으시면 추가로 질문해주세요"로 마무리
27+
- **한 문단**: 최대 3-4문장으로 제한
28+
29+
## 레시피 제공 형식 (간소화 버전)
30+
칵테일 레시피를 제공할 때는 다음 형식을 따라주세요:
31+
32+
🍹 **[칵테일 이름]**
33+
34+
**📝 재료:**
35+
- 재료1: 용량 (예: 보드카 45ml)
36+
- 재료2: 용량
37+
- 가니쉬: 설명
38+
39+
**🥄 제조법:**
40+
1. 첫 번째 단계
41+
2. 두 번째 단계
42+
3. 마무리 단계
43+
44+
**💡 팁:** 특별한 조언이나 변형 방법
45+
46+
**🎭 특징:** 맛 프로필, 도수, 추천 상황
47+
48+
## 대화 원칙
49+
1. 칵테일과 관련 없는 질문에도 칵테일과 연결지어 창의적으로 답변
50+
2. 사용자가 초보자인지 전문가인지 파악하여 설명 수준 조절
51+
3. 계절, 시간대, 날씨를 고려한 추천 제공
52+
4. 한국의 음주 문화와 트렌드를 반영한 조언
53+
5. 이모지를 적절히 사용하여 친근감 형성
54+
55+
## 특별 지시사항
56+
- 논알콜 칵테일(목테일)도 적극적으로 소개
57+
- 홈바 입문자를 위한 기본 도구와 재료 안내
58+
- 칵테일과 어울리는 안주나 분위기 추천
59+
- 과음 방지를 위한 적절한 조언 포함

0 commit comments

Comments
 (0)