11package com .example .talky .domain .recommendation .service ;
22
3- import com .example .talky .adapter .ai .AiServerClient ;
4- import com .example .talky .adapter .ai .response .RecommendationResponse ;
3+ import com .example .talky .global .ai .FastApiClient ;
54import com .example .talky .domain .auth .entity .NormalUser ;
65import com .example .talky .domain .auth .exception .UserNotFoundException ;
76import com .example .talky .domain .auth .repository .UserRepository ;
87import com .example .talky .domain .favorites .entity .Favorite ;
98import com .example .talky .domain .favorites .exception .FavoriteNorFoundException ;
109import com .example .talky .domain .favorites .repository .FavoriteRepository ;
11- import com .example .talky .domain .recommendation .entity .Speech ;
1210import com .example .talky .domain .recommendation .entity .Conversation ;
11+ import com .example .talky .domain .recommendation .entity .Speech ;
1312import com .example .talky .domain .recommendation .repository .ConversationRepository ;
1413import com .example .talky .domain .recommendation .repository .SpeechRepository ;
1514import com .example .talky .domain .recommendation .web .dto .GetContextReq ;
16- import com .example .talky .global .ai .dto .AiRcmdRes ;
1715import com .example .talky .global .ai .dto .ToAiReq ;
18- import com .example .talky .global .response .SuccessResponse ;
16+ import com .example .talky .global .ai .dto .AiRcmdRes ;
17+ import com .fasterxml .jackson .core .JsonProcessingException ;
18+ import com .fasterxml .jackson .databind .ObjectMapper ;
1919import jakarta .transaction .Transactional ;
2020import lombok .RequiredArgsConstructor ;
2121import lombok .extern .slf4j .Slf4j ;
22- import org .springframework .http .HttpStatus ;
23- import org .springframework .http .ResponseEntity ;
2422import org .springframework .stereotype .Service ;
23+ import org .springframework .web .multipart .MultipartFile ;
2524
2625import java .util .ArrayList ;
2726import java .util .List ;
3231@ RequiredArgsConstructor
3332public class RcmdServiceImpl implements RcmdService {
3433
35- private final AiServerClient aiServerClient ;
34+ private final FastApiClient fastApiClient ;
3635 private final UserRepository userRepository ;
3736 private final FavoriteRepository favoriteRepository ;
3837 private final ConversationRepository conversationRepository ; // AI 추적용
3938 private final SpeechRepository speechRepository ; // 별도 API용
39+ private final ObjectMapper objectMapper ;
4040
4141 @ Transactional
4242 @ Override
43- public AiRcmdRes getAiRcmd (GetContextReq req , Long normalId ) {
43+ public AiRcmdRes getAiRcmd (MultipartFile file , String metadataJson , Long normalId ) throws JsonProcessingException {
44+ // 메타데이터 JSON 파싱
45+ GetContextReq req = objectMapper .readValue (metadataJson , GetContextReq .class );
4446 String choose = req .getChoose ();
4547
4648 // choose == null -> drop all record(새로운 user 대화 이력 테이블 사용)
@@ -71,11 +73,9 @@ public AiRcmdRes getAiRcmd(GetContextReq req, Long normalId) {
7173
7274 if (req .getChoose () != null && req .getSttMessage () != null ) {
7375 tracking .addFirst (req .getChoose ());
74- tracking .addFirst (req .getSttMessage ());
75- } else if (req .getSttMessage () != null ) {
76- tracking .add (req .getSttMessage ());
7776 }
7877
78+ // 변경된 대화 기록 저장
7979 conversation .modify (tracking );
8080
8181 // Context 3 - 데이터베이스에 저장
@@ -97,32 +97,30 @@ public AiRcmdRes getAiRcmd(GetContextReq req, Long normalId) {
9797 .map (Favorite ::getSentence )
9898 .toList ();
9999
100- // 이전 대화 기록이 없을 시 NPE 예외 던지는 중임
101- List <String > conversations = conversation .getConversations ();
100+ // AI 서버로 보낼 요청 객체 (ToAiReq) 생성
101+ // sttMessage는 현재 턴에서는 AI 서버가 파일로부터 생성하므로 null로 설정
102+ ToAiReq toAiReq = ToAiReq .builder ()
103+ .keywords (req .getKeywords ())
104+ .context (req .getContext ())
105+ .choose (choose )
106+ .conversation (conversation .getConversations ())
107+ .favorites (favorites )
108+ .sttMessage (null )
109+ .build ();
110+
111+ // AI 서버 호출
112+ AiRcmdRes response = fastApiClient .getAiRecommendation (toAiReq , file );
113+ String category = response .getCategory ();
114+ String sttResultFromAi = response .getSttMessage (); // AI 서버로부터 STT 결과 수신
102115
103- ToAiReq toAiReq ;
104- log .info ("choose={}, conversations={}" , choose , conversations );
105- if (choose == null && conversations == null ) {
106- //log.info("잘못 들어옴");
107- toAiReq = ToAiReq .builder ()
108- .keywords (req .getKeywords ())
109- .context (req .getContext ())
110- .build ();
116+ // AI 서버에서 받은 STT 결과를 다음 턴의 컨텍스트를 위해 대화 기록에 추가
117+ if (sttResultFromAi != null ) {
118+ tracking .add (sttResultFromAi );
119+ conversation .modify (tracking );
120+ conversationRepository .saveAndFlush (conversation );
111121 }
112- else {
113- //log.info("잘 들어왓음");
114- toAiReq = ToAiReq .builder ()
115- .keywords (req .getKeywords ())
116- .context (req .getContext ())
117- .conversations (conversations )
118- .favorites (favorites )
119- .sttMessage (req .getSttMessage ())
120- .build ();
121- }
122- log .info (toAiReq .toString ());
123- AiRcmdRes response = aiServerClient .getAiRcmdSentences (toAiReq );
124- // 카테고리 획득
125- String category = response .getCategory ();
122+
123+ // 음성 기록 저장 (통계용)
126124 speechRepository .save (Speech .builder ()
127125 .normalUser ((NormalUser ) userRepository .findById (normalId )
128126 .orElseThrow (UserNotFoundException ::new ))
@@ -133,6 +131,7 @@ public AiRcmdRes getAiRcmd(GetContextReq req, Long normalId) {
133131 }
134132
135133 private boolean favoriteIsPresent (Long normalId , String choose ) {
134+ if (choose == null ) return false ;
136135 return favoriteRepository .findByNormalUserIdAndSentence (normalId , choose ).isPresent ();
137136 }
138137}
0 commit comments