Skip to content

Commit 54d724c

Browse files
committed
feat: clova-> gpt 모델 변경
1 parent 2ab05d5 commit 54d724c

File tree

10 files changed

+222
-51
lines changed

10 files changed

+222
-51
lines changed

api/src/main/java/com/mbtips/message/application/manager/MessageManager.java

Lines changed: 82 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
import com.fasterxml.jackson.databind.ObjectMapper;
55
import com.mbtips.clova.client.ClovaApiFeignClient;
66
import com.mbtips.clova.dto.ChatRequest;
7-
import com.mbtips.clova.dto.ClovaApiResponse;
8-
import com.mbtips.common.mbtiinfo.MbtiTraits;
9-
import com.mbtips.common.mbtiinfo.MbtiType;
107
import com.mbtips.common.provider.ClovaApiKeyProvider;
8+
import com.mbtips.common.provider.GptApiKeyProvider;
119
import com.mbtips.conversation.interfaces.ConversationRepository;
1210
import com.mbtips.domain.conversation.service.ConversationService;
1311
import com.mbtips.domain.converstation.Conversation;
@@ -16,13 +14,19 @@
1614
import com.mbtips.domain.message.dto.response.GetMessageResponseDto;
1715
import com.mbtips.domain.user.User;
1816
import com.mbtips.domain.virtualfriend.VirtualFriend;
17+
import com.mbtips.gpt.client.GptApiFeignClient;
18+
import com.mbtips.gpt.dto.GptChatRequest;
19+
import com.mbtips.gpt.dto.GptResponse;
1920
import com.mbtips.message.application.service.MessageService;
2021
import lombok.RequiredArgsConstructor;
2122
import lombok.extern.slf4j.Slf4j;
2223
import org.springframework.stereotype.Service;
2324
import org.springframework.transaction.annotation.Transactional;
2425

25-
import java.util.*;
26+
import java.util.Arrays;
27+
import java.util.Collections;
28+
import java.util.List;
29+
import java.util.Map;
2630

2731
@Service
2832
@RequiredArgsConstructor
@@ -36,56 +40,60 @@ public class MessageManager {
3640
private final ClovaApiKeyProvider clovaApiKeyProvider;
3741
private final ConversationRepository conversationRepository;
3842
private final ObjectMapper objectMapper;
43+
private final GptApiFeignClient gptApiFeignClient;
44+
private final GptApiKeyProvider gptApiKeyProvider;
3945

4046
@Transactional
41-
public String sendMessage(User user, CreateMessageRequestDto createMessageRequestDto) {
42-
Conversation conversation = conversationService.findById(createMessageRequestDto.conversationId());
43-
List<GetMessageResponseDto> messages = messageService.getRecentMessagesOfConversationId(conversation.getConversationId());
44-
Collections.reverse(messages);
45-
//log.debug("<<<service start >>> userInfo : {}", user);
46-
Message requestMessage = Message.builder()
47-
.user(user)
48-
.conversation(conversation)
49-
// .virtualFriend(conversation.getVirtualFriend())
50-
.messageContent(createMessageRequestDto.messageContent())
51-
.build();
52-
log.debug("message : {}", requestMessage.toString());
53-
messageService.saveMessage(requestMessage);
54-
47+
public String sendMessage(User user, CreateMessageRequestDto dto) {
48+
Conversation conversation = conversationService.findById(dto.conversationId());
49+
List<GetMessageResponseDto> recentMessages = messageService.getRecentMessagesOfConversationId(conversation.getConversationId());
5550

56-
String prompt = makePrompt(createMessageRequestDto.conversationId());
51+
// 사용자 메시지 저장
52+
Message userMessage = Message.createMessage(user, conversation, dto.messageContent());
53+
messageService.saveMessage(userMessage);
5754

58-
String recentMessagesPrompt = makeRecentMessageString(messages);
59-
prompt += recentMessagesPrompt;
60-
prompt = prompt + " 이제 대화를 시작해보자!";
61-
log.debug("prompt : {} ", prompt);
55+
// 프롬프트 생성
56+
String prompt = buildFullPrompt(conversation, recentMessages, dto.messageContent());
57+
log.debug("Final Prompt: {}", prompt);
6258

63-
String responseContent = messageRequest(prompt + " " + createMessageRequestDto.messageContent());
64-
log.debug("responseMessage : {} ", responseContent);
59+
// 메시지 응답 요청
60+
String responseContent = messageRequest(prompt);
61+
log.debug("Response Message: {}", responseContent);
6562

6663

67-
Message responseMessage = Message.builder()
68-
.conversation(conversation)
69-
.virtualFriend(conversation.getVirtualFriend())
70-
.messageContent(responseContent)
71-
.build();
72-
64+
Message responseMessage = Message.createMessage(conversation, responseContent);
7365
messageService.saveMessage(responseMessage);
66+
7467
return responseContent;
7568
}
7669

70+
private String buildFullPrompt(Conversation conversation, List<GetMessageResponseDto> recentMessages, String userMessage) {
71+
String basePrompt = makePrompt(conversation.getConversationId());
72+
String recentMessageSummary = makeRecentMessageString(recentMessages);
73+
74+
log.debug("Base Prompt: {}", basePrompt);
75+
log.debug("Recent Messages: {}", recentMessageSummary);
76+
77+
String mbtiStyle = conversation.getVirtualFriend().getMbti();
78+
String suffix = " 이제 대화를 시작해보자!";
79+
String instruction = "이제 들어온 톡은 아래와 같은데 " + mbtiStyle + "스타일 친구 같이 무례하지 않은 반말로 대답해봐";
80+
81+
return basePrompt + recentMessageSummary + suffix + " " + instruction + " " + userMessage;
82+
}
83+
7784
private String makeRecentMessageString(List<GetMessageResponseDto> messages) {
85+
Collections.reverse(messages);
7886
StringBuilder messageBuilder = new StringBuilder();
79-
messageBuilder.append(" 지금까지의 대화내용은 다음과 같아. B가 지금까지 너의 대답이야. ");
87+
messageBuilder.append(" 지금까지 너와 상대방은 이런 대화를 해왔어 ");
8088
int idx = messages.size() - 6;
8189
if(idx < 0) idx = 0;
8290
for(int i = idx; i < messages.size(); i++){
8391
if(messages.get(i).userId() != null) {
84-
messageBuilder.append("A : ");
92+
messageBuilder.append(" 상대방 : ");
8593
messageBuilder.append(messages.get(i).messageContent());
8694
}
8795
if(messages.get(i).virtualFriendId() != null) {
88-
messageBuilder.append("B : ");
96+
messageBuilder.append(" : ");
8997
messageBuilder.append(messages.get(i).messageContent());
9098
}
9199
if(i != messages.size() -1 ) messageBuilder.append(", ");
@@ -102,14 +110,13 @@ private String makePrompt(Long conversationId) {
102110
String mbti = virtualFriend.getMbti();
103111
// MbtiType mbtiType = MbtiType.valueOf(mbti);
104112
// String result = MbtiTraits.getTrait(mbtiType);
105-
String result = "너는 이제부터 MBTI중 " + mbti + "에 해당하는 사람이야. 답변은 10~30자 내외로 대답해줘.";
106-
// 너는 이제부터 MBTI 중 ENFP에 해당하는 사람이야. 답변은 10~30자 내외로 대답해줘.
113+
String result = "지금부터 너는 " + mbti + "스타일의 친구야. 너의 페르소나에 몰입해서 상대방과 대화해야 해.";
107114

108115
StringBuilder temp = new StringBuilder();
109-
if(virtualFriend.getName() != null) temp.append(" 너의 이름은 " + virtualFriend.getName() +"이야. 명심해!");
110-
if(virtualFriend.getAge() != 0) temp.append(" 너의 나이는 " + virtualFriend.getAge() + "이야. ");
111-
if(virtualFriend.getGender() != null) temp.append(" 너의 성별은 " + virtualFriend.getGender() + "이야. ");
112-
if(virtualFriend.getRelationship() != null) temp.append("너와 나의 관계는 " + virtualFriend.getRelationship() + "이야");
116+
if(virtualFriend.getName() != null) temp.append(" 너의 이름은 " + virtualFriend.getName() +"야.");
117+
if(virtualFriend.getAge() != 0) temp.append(" 너의 나잇대는 " + virtualFriend.getAge() + "야.");
118+
if(virtualFriend.getGender() != null) temp.append(" 너의 성별은 " + virtualFriend.getGender() + "이야.");
119+
// if(virtualFriend.getRelationship() != null) temp.append(" 너와 나의 관계는 " + virtualFriend.getRelationship() + "이야");
113120

114121
result += temp.toString();
115122
return result;
@@ -119,21 +126,48 @@ private String makePrompt(Long conversationId) {
119126
public String messageRequest(String content){
120127
com.mbtips.clova.dto.Message message = new com.mbtips.clova.dto.Message("user", content);
121128
ChatRequest chatRequest = new ChatRequest(Arrays.asList(message), MAX_TOKEN_VALUE);
122-
String apiResult = clovaApiFeignClient.getResponse(
123-
"Bearer " + clovaApiKeyProvider.apiKey(),
124-
UUID.randomUUID().toString(),
125-
chatRequest
129+
// String apiResult = clovaApiFeignClient.getResponse(
130+
// "Bearer " + clovaApiKeyProvider.apiKey(),
131+
// UUID.randomUUID().toString(),
132+
// chatRequest
133+
// );
134+
// List<com.mbtips.clova.dto.Message> messages = List.of(
135+
// new com.mbtips.clova.dto.Message("user", "Write a poem about coffee.")
136+
// );
137+
List<com.mbtips.clova.dto.Message> messages = List.of(
138+
new com.mbtips.clova.dto.Message("user", content)
139+
);
140+
String response = gptApiFeignClient.getResponse(
141+
"Bearer " + gptApiKeyProvider.apiKey(),
142+
GptChatRequest.builder()
143+
.model("gpt-4o-mini")
144+
.messages(messages)
145+
.temperature(0.7)
146+
.max_tokens(100)
147+
.build()
126148
);
127149

128-
log.debug("clovaResponse : {}" , apiResult);
129150
String resultResponse = "";
130151
try {
131-
ClovaApiResponse clovaApiResponse = objectMapper.readValue(apiResult, ClovaApiResponse.class);
132-
resultResponse = clovaApiResponse.getResult().getMessage().getContent();
152+
ObjectMapper objectMapper = new ObjectMapper();
153+
GptResponse gptResponse = objectMapper.readValue(response, GptResponse.class);
154+
resultResponse = gptResponse.choices.get(0).message.content;
133155
} catch (JsonProcessingException e) {
134-
throw new RuntimeException(e);
156+
throw new RuntimeException("Failed to parse GPT response", e);
135157
}
158+
log.debug("gptResposne : {}", resultResponse);
136159
return resultResponse;
137160
}
138161

162+
public List<Map<String, Object>> modelList() {
163+
log.debug("[+] 모델 리스트를 조회합니다.");
164+
List<Map<String, Object>> resultList = null;
165+
166+
String response = gptApiFeignClient.getModelList(
167+
"Bearer " + gptApiKeyProvider.apiKey()
168+
);
169+
System.out.println(resultList);
170+
return resultList;
171+
}
172+
139173
}

api/src/main/java/com/mbtips/message/controller/MessageController.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import com.mbtips.domain.message.dto.response.GetMessageResponseDto;
1212
import lombok.RequiredArgsConstructor;
1313
import lombok.extern.slf4j.Slf4j;
14+
import org.springframework.http.HttpStatus;
15+
import org.springframework.http.ResponseEntity;
1416
import org.springframework.web.bind.annotation.*;
1517

1618
import java.util.List;
@@ -40,4 +42,10 @@ public ApiResponse<String> createMessage(@RequestBody CreateMessageRequestDto cr
4042
return ApiResponse.success(clovaResponse);
4143
}
4244

45+
@GetMapping("/modellist")
46+
public ResponseEntity<List<Map<String, Object>>> selectModelList() {
47+
List<Map<String, Object>> result = messageManager.modelList();
48+
return new ResponseEntity<>(result, HttpStatus.OK);
49+
}
50+
4351
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.mbtips.common.provider;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.springframework.beans.factory.annotation.Value;
5+
import org.springframework.stereotype.Component;
6+
7+
@Component
8+
@RequiredArgsConstructor
9+
public class GptApiKeyProvider {
10+
11+
@Value("${gpt.api-key}")
12+
private String apiKey;
13+
14+
public String apiKey(){
15+
return apiKey;
16+
}
17+
18+
}

core/src/main/java/com/mbtips/domain/message/Message.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,19 @@ public class Message {
2828

2929
private Boolean isRead;
3030

31+
public static Message createMessage(User user, Conversation conversation, String messageContent){
32+
return Message.builder()
33+
.user(user)
34+
.conversation(conversation)
35+
.messageContent(messageContent)
36+
.build();
37+
}
38+
39+
public static Message createMessage(Conversation conversation, String messageContent){
40+
return Message.builder()
41+
.conversation(conversation)
42+
.virtualFriend(conversation.getVirtualFriend())
43+
.messageContent(messageContent)
44+
.build();
45+
}
3146
}

core/src/main/resources/local/application-core.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ jwt:
22
secret: ENC(sSC+btxCYkHvPLQQhuMtDqg67p925zdtl3nKAnRmDzxLRZGu3uUVFcpnGrYPA8AwHH0jTd8T1ec=)
33
expiration: 3600000
44
clova:
5-
api-key: ENC(PU+ICOCY668/ul4RJV2fp3eBtJli1nyJgQB5mU873SMItpflkRAG0Sa0KMgCDmPx)
5+
api-key: ENC(PU+ICOCY668/ul4RJV2fp3eBtJli1nyJgQB5mU873SMItpflkRAG0Sa0KMgCDmPx)
6+
gpt:
7+
api-key: ENC(txY6IXHUbivTtHKcPkmQGkrQYiZylv5l8hiV3i+opo4HhKRaYaJoEIleiis0ZzXg10bPF6rfqeUcovgxqLuAy6otSYtDclxBrKE433nc4Zeku4IJ/kzRk2/mnAJn/rYx5imRZAYOw0GV3zRr688RM5bZOI/Wq6f9Sv0KzfHeWkrF6RGr/ocO48Dr2NsC/6QEYHykfgd69p5JNcIwJU/yiaLyBNQuJvr27KlV1tTgrEI=)

core/src/main/resources/prod/application-core.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ jwt:
22
secret: ENC(sSC+btxCYkHvPLQQhuMtDqg67p925zdtl3nKAnRmDzxLRZGu3uUVFcpnGrYPA8AwHH0jTd8T1ec=)
33
expiration: 3600000
44
clova:
5-
api-key: ENC(PU+ICOCY668/ul4RJV2fp3eBtJli1nyJgQB5mU873SMItpflkRAG0Sa0KMgCDmPx)
5+
api-key: ENC(PU+ICOCY668/ul4RJV2fp3eBtJli1nyJgQB5mU873SMItpflkRAG0Sa0KMgCDmPx)
6+
gpt:
7+
api-key: ENC(txY6IXHUbivTtHKcPkmQGkrQYiZylv5l8hiV3i+opo4HhKRaYaJoEIleiis0ZzXg10bPF6rfqeUcovgxqLuAy6otSYtDclxBrKE433nc4Zeku4IJ/kzRk2/mnAJn/rYx5imRZAYOw0GV3zRr688RM5bZOI/Wq6f9Sv0KzfHeWkrF6RGr/ocO48Dr2NsC/6QEYHykfgd69p5JNcIwJU/yiaLyBNQuJvr27KlV1tTgrEI=)

core/src/test/java/com/mbtips/common/configuration/JasyptConfigurationTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ void giveStringAndPasswordWhenEncryptAndDecryptThenSameTrue(){
3131

3232
// when
3333
String encrypt = this.jasyptEncrypt(target);
34+
System.out.println("encrypt = " + encrypt);
3435
String decrypt = this.jasyptDecrypt(encrypt);
35-
36+
System.out.println("decrypt = " + decrypt);
3637
// then
3738
Assertions.assertEquals(target, decrypt);
3839
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.mbtips.gpt.client;
2+
3+
import com.mbtips.gpt.dto.GptChatRequest;
4+
import org.springframework.cloud.openfeign.FeignClient;
5+
import org.springframework.http.MediaType;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.PostMapping;
8+
import org.springframework.web.bind.annotation.RequestBody;
9+
import org.springframework.web.bind.annotation.RequestHeader;
10+
11+
@FeignClient(name = "gpt-chat", url = "https://api.openai.com/v1")
12+
public interface GptApiFeignClient {
13+
14+
@PostMapping(value = "/chat/completions", consumes = MediaType.APPLICATION_JSON_VALUE)
15+
String getResponse(
16+
@RequestHeader("Authorization") String authorization,
17+
@RequestBody GptChatRequest request
18+
);
19+
20+
@GetMapping(value = "/models", consumes = MediaType.APPLICATION_JSON_VALUE)
21+
String getModelList(
22+
@RequestHeader("Authorization") String authorization
23+
);
24+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.mbtips.gpt.dto;
2+
3+
import com.mbtips.clova.dto.Message;
4+
import lombok.*;
5+
6+
import java.util.List;
7+
8+
@Getter
9+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
10+
@AllArgsConstructor
11+
@Builder
12+
public class GptChatRequest {
13+
14+
private String model;
15+
private List<Message> messages;
16+
private Double temperature;
17+
private Integer max_tokens;
18+
19+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.mbtips.gpt.dto;
2+
3+
import java.util.List;
4+
5+
public class GptResponse {
6+
public String id;
7+
public String object;
8+
public long created;
9+
public String model;
10+
public List<Choice> choices;
11+
public Usage usage;
12+
public String service_tier;
13+
public String system_fingerprint;
14+
15+
public static class Choice {
16+
public int index;
17+
public Message message;
18+
public Object logprobs;
19+
public String finish_reason;
20+
}
21+
22+
public static class Message {
23+
public String role;
24+
public String content;
25+
public Object refusal;
26+
public List<Object> annotations;
27+
}
28+
29+
public static class Usage {
30+
public int prompt_tokens;
31+
public int completion_tokens;
32+
public int total_tokens;
33+
public PromptTokensDetails prompt_tokens_details;
34+
public CompletionTokensDetails completion_tokens_details;
35+
}
36+
37+
public static class PromptTokensDetails {
38+
public int cached_tokens;
39+
public int audio_tokens;
40+
}
41+
42+
public static class CompletionTokensDetails {
43+
public int reasoning_tokens;
44+
public int audio_tokens;
45+
public int accepted_prediction_tokens;
46+
public int rejected_prediction_tokens;
47+
}
48+
}

0 commit comments

Comments
 (0)