11package io .wisoft .prepair .prepair_api .interview .answer .event ;
22
33import io .wisoft .prepair .prepair_api .interview .answer .dto .CombinedFeedbackResult ;
4- import java .io .IOException ;
5- import java .nio .file .Files ;
6- import java .nio .file .Path ;
74import io .wisoft .prepair .prepair_api .interview .answer .dto .FinalFeedbackResult ;
85import io .wisoft .prepair .prepair_api .interview .answer .dto .FinalFeedbackResponse ;
96import io .wisoft .prepair .prepair_api .interview .answer .entity .InterviewAnswer ;
107import io .wisoft .prepair .prepair_api .interview .answer .entity .InterviewFeedback ;
11- import io .wisoft .prepair .prepair_api .interview .question .entity .InterviewQuestion ;
12- import io .wisoft .prepair .prepair_api .interview .session .entity .InterviewSession ;
138import io .wisoft .prepair .prepair_api .interview .answer .entity .FeedbackType ;
149import io .wisoft .prepair .prepair_api .interview .answer .repository .AnswerRepository ;
1510import io .wisoft .prepair .prepair_api .interview .answer .repository .FeedbackRepository ;
16- import io .wisoft .prepair .prepair_api .interview .question .repository .QuestionRepository ;
17- import io .wisoft .prepair .prepair_api .interview .session .repository .SessionRepository ;
1811import io .wisoft .prepair .prepair_api .interview .answer .service .AnswerPersistenceService ;
1912import io .wisoft .prepair .prepair_api .interview .answer .service .FeedbackGenerator ;
13+ import io .wisoft .prepair .prepair_api .interview .question .entity .InterviewQuestion ;
14+ import io .wisoft .prepair .prepair_api .interview .question .repository .QuestionRepository ;
15+ import io .wisoft .prepair .prepair_api .interview .session .entity .InterviewSession ;
16+ import io .wisoft .prepair .prepair_api .interview .session .repository .SessionRepository ;
2017import io .wisoft .prepair .prepair_api .common .support .SseEmitterManager ;
2118import lombok .RequiredArgsConstructor ;
2219import lombok .extern .slf4j .Slf4j ;
2522import org .springframework .stereotype .Component ;
2623import org .springframework .transaction .annotation .Transactional ;
2724
25+ import java .io .IOException ;
26+ import java .nio .file .Files ;
27+ import java .nio .file .Path ;
2828import java .util .ArrayList ;
2929import java .util .List ;
3030import java .util .Map ;
31+ import java .util .Optional ;
3132import java .util .UUID ;
33+ import java .util .stream .Collectors ;
3234
3335@ Slf4j
3436@ Component
@@ -48,92 +50,133 @@ public class AllAnalysisCompletedHandler {
4850 @ Transactional
4951 public void handle (AllAnalysisCompletedEvent event ) {
5052 UUID answerId = event .answerId ();
51-
5253 deleteTempFile (event .videoPath ());
5354
5455 if (event .hasFailed ()) {
5556 log .error ("[종합평가] 분석 실패로 종합평가 생략 - answerId: {}" , answerId );
56- sendFailureToSession (answerId , "분석 중 오류가 발생했습니다." );
57+ failSession (answerId , "분석 중 오류가 발생했습니다." );
5758 return ;
5859 }
5960
6061 try {
61- List <InterviewFeedback > feedbacks = feedbackRepository .findByInterviewAnswerId (answerId );
62-
63- InterviewFeedback sttFeedback = feedbacks .stream ()
64- .filter (f -> f .getFeedbackType () == FeedbackType .STT )
65- .findFirst ().orElse (null );
66-
67- InterviewFeedback videoFeedback = feedbacks .stream ()
68- .filter (f -> f .getFeedbackType () == FeedbackType .VIDEO )
69- .findFirst ().orElse (null );
70-
71- if (sttFeedback == null || videoFeedback == null ) {
72- log .error ("[종합평가] STT 또는 Video 피드백 없음 - answerId: {}" , answerId );
62+ Optional <AnalysisFeedbacks > feedbacksOpt = findAnalysisFeedbacks (answerId );
63+ if (feedbacksOpt .isEmpty ()) {
64+ failSession (answerId , "분석 결과가 누락되어 종합 평가를 생성할 수 없습니다." );
7365 return ;
7466 }
7567
7668 InterviewAnswer answer = answerRepository .findByIdWithQuestionAndSession (answerId ).orElse (null );
77- if (answer == null ) {
78- return ;
79- }
80-
81- String question = answer .getInterviewQuestion ().getQuestion ();
82-
83- CombinedFeedbackResult result = feedbackGenerator .generateCombined (
84- question ,
85- sttFeedback .getFeedback (),
86- videoFeedback .getFeedback ()
87- );
69+ if (answer == null ) return ;
8870
89- answerPersistenceService . saveCombinedFeedback (answerId , result );
90- log . info ( "[종합평가] 완료 - answerId: {}, score: {}" , answerId , result . score () );
71+ saveCombinedFeedback (answerId , answer , feedbacksOpt . get () );
72+ tryGenerateFinalFeedback ( answer );
9173
92- checkAndGenerateFinal (answer );
9374 } catch (Exception e ) {
9475 log .error ("[종합평가] 실패 - answerId: {}, error: {}" , answerId , e .getMessage (), e );
95- sendFailureToSession (answerId , "종합 평가 생성 중 오류가 발생했습니다." );
76+ failSession (answerId , "종합 평가 생성 중 오류가 발생했습니다." );
9677 }
9778 }
9879
99- private void checkAndGenerateFinal (InterviewAnswer answer ) {
80+ private Optional <AnalysisFeedbacks > findAnalysisFeedbacks (UUID answerId ) {
81+ List <InterviewFeedback > feedbacks = feedbackRepository .findByInterviewAnswerId (answerId );
82+
83+ InterviewFeedback stt = feedbacks .stream ()
84+ .filter (f -> f .getFeedbackType () == FeedbackType .STT )
85+ .findFirst ()
86+ .orElse (null );
87+
88+ InterviewFeedback video = feedbacks .stream ()
89+ .filter (f -> f .getFeedbackType () == FeedbackType .VIDEO )
90+ .findFirst ()
91+ .orElse (null );
92+
93+ if (stt == null || video == null ) {
94+ log .error ("[종합평가] STT 또는 Video 피드백 없음 - answerId: {}" , answerId );
95+ return Optional .empty ();
96+ }
97+
98+ return Optional .of (new AnalysisFeedbacks (stt , video ));
99+ }
100+
101+ private void saveCombinedFeedback (UUID answerId , InterviewAnswer answer , AnalysisFeedbacks feedbacks ) {
102+ String question = answer .getInterviewQuestion ().getQuestion ();
103+
104+ CombinedFeedbackResult result = feedbackGenerator .generateCombined (
105+ question ,
106+ feedbacks .stt ().getFeedback (),
107+ feedbacks .video ().getFeedback ()
108+ );
109+
110+ answerPersistenceService .saveCombinedFeedback (answerId , result );
111+ log .info ("[종합평가] 완료 - answerId: {}, score: {}" , answerId , result .score ());
112+ }
113+
114+ private void tryGenerateFinalFeedback (InterviewAnswer answer ) {
100115 InterviewSession session = answer .getInterviewQuestion ().getInterviewSession ();
101116 if (session == null ) {
102117 log .warn ("[최종평가] 세션 없음 - answerId: {}" , answer .getId ());
103118 return ;
104119 }
105120
106121 UUID sessionId = session .getId ();
122+ if (!isFinalFeedbackReady (sessionId , session .getTotalQuestionCount ())) return ;
123+
124+ List <InterviewQuestion > questions = questionRepository .findByInterviewSessionId (sessionId );
125+
126+ Map <UUID , InterviewAnswer > answerMap = answerRepository .findBySessionId (sessionId ).stream ()
127+ .collect (Collectors .toMap (a -> a .getInterviewQuestion ().getId (), a -> a ));
128+
129+ Map <UUID , List <InterviewFeedback >> feedbackMap = feedbackRepository .findAllBySessionId (sessionId ).stream ()
130+ .collect (Collectors .groupingBy (f -> f .getInterviewAnswer ().getId ()));
131+
132+ FinalFeedbackData data = buildFinalData (questions , answerMap , feedbackMap );
133+ FinalFeedbackResult finalResult = feedbackGenerator .generateFinal (data .promptInput ());
134+
135+ completeSession (session , data , finalResult );
136+ }
137+
138+ private boolean isFinalFeedbackReady (UUID sessionId , int totalQuestionCount ) {
107139 long combinedCount = feedbackRepository .countBySessionIdAndFeedbackType (sessionId , FeedbackType .COMBINED );
108140
109- if (combinedCount < session . getTotalQuestionCount () ) {
110- log .info ("[최종평가] 아직 모든 질문 완료되지 않음 - sessionId: {}, {}/{}" , sessionId , combinedCount , session . getTotalQuestionCount () );
111- return ;
141+ if (combinedCount < totalQuestionCount ) {
142+ log .info ("[최종평가] 아직 모든 질문 완료되지 않음 - sessionId: {}, {}/{}" , sessionId , combinedCount , totalQuestionCount );
143+ return false ;
112144 }
145+ return true ;
146+ }
113147
114- List <InterviewQuestion > questions = questionRepository .findByInterviewSessionId (sessionId );
115-
148+ private FinalFeedbackData buildFinalData (
149+ List <InterviewQuestion > questions ,
150+ Map <UUID , InterviewAnswer > answerMap ,
151+ Map <UUID , List <InterviewFeedback >> feedbackMap
152+ ) {
116153 StringBuilder promptInput = new StringBuilder ();
117154 List <FinalFeedbackResponse .QuestionFeedback > questionFeedbacks = new ArrayList <>();
118155 int totalScore = 0 ;
119156
120157 for (InterviewQuestion q : questions ) {
121- InterviewAnswer ans = answerRepository . findByInterviewQuestionId (q .getId ()). orElse ( null );
158+ InterviewAnswer ans = answerMap . get (q .getId ());
122159 if (ans == null ) continue ;
123160
124- List <InterviewFeedback > answerFeedbacks = feedbackRepository . findByInterviewAnswerId (ans .getId ());
161+ List <InterviewFeedback > answerFeedbacks = feedbackMap . getOrDefault (ans .getId (), List . of ());
125162
126163 InterviewFeedback combined = answerFeedbacks .stream ()
127- .filter (f -> f .getFeedbackType () == FeedbackType .COMBINED ).findFirst ().orElse (null );
164+ .filter (f -> f .getFeedbackType () == FeedbackType .COMBINED )
165+ .findFirst ()
166+ .orElse (null );
128167 if (combined == null ) continue ;
129168
130169 String sttFeedbackStr = answerFeedbacks .stream ()
131- .filter (f -> f .getFeedbackType () == FeedbackType .STT ).findFirst ()
132- .map (InterviewFeedback ::getFeedback ).orElse (null );
170+ .filter (f -> f .getFeedbackType () == FeedbackType .STT )
171+ .findFirst ()
172+ .map (InterviewFeedback ::getFeedback )
173+ .orElse (null );
133174
134175 String videoFeedbackStr = answerFeedbacks .stream ()
135- .filter (f -> f .getFeedbackType () == FeedbackType .VIDEO ).findFirst ()
136- .map (InterviewFeedback ::getFeedback ).orElse (null );
176+ .filter (f -> f .getFeedbackType () == FeedbackType .VIDEO )
177+ .findFirst ()
178+ .map (InterviewFeedback ::getFeedback )
179+ .orElse (null );
137180
138181 promptInput .append ("질문: " ).append (q .getQuestion ()).append ("\n " );
139182 promptInput .append ("종합 평가: " ).append (combined .getFeedback ()).append ("\n " );
@@ -152,23 +195,38 @@ private void checkAndGenerateFinal(InterviewAnswer answer) {
152195 }
153196
154197 int finalScore = questionFeedbacks .isEmpty () ? 0 : totalScore / questionFeedbacks .size ();
198+ return new FinalFeedbackData (promptInput .toString (), questionFeedbacks , finalScore );
199+ }
155200
156- FinalFeedbackResult finalResult = feedbackGenerator .generateFinal (promptInput .toString ());
201+ private void completeSession (InterviewSession session , FinalFeedbackData data , FinalFeedbackResult finalResult ) {
202+ UUID sessionId = session .getId ();
157203
158- session .complete (finalScore , finalResult .finalFeedback ());
204+ session .complete (data . finalScore () , finalResult .finalFeedback ());
159205 sessionRepository .save (session );
160206
161207 FinalFeedbackResponse response = new FinalFeedbackResponse (
162208 sessionId ,
163- finalScore ,
209+ data . finalScore () ,
164210 finalResult .finalFeedback (),
165- questionFeedbacks
211+ data . questionFeedbacks ()
166212 );
167213
168214 sseEmitterManager .send (sessionId , "final-complete" , response );
169215 sseEmitterManager .complete (sessionId );
170216
171- log .info ("[최종평가] 완료 - sessionId: {}, finalScore: {}" , sessionId , finalScore );
217+ log .info ("[최종평가] 완료 - sessionId: {}, finalScore: {}" , sessionId , data .finalScore ());
218+ }
219+
220+ private void failSession (UUID answerId , String message ) {
221+ InterviewAnswer answer = answerRepository .findByIdWithQuestionAndSession (answerId ).orElse (null );
222+ if (answer == null || answer .getInterviewQuestion ().getInterviewSession () == null ) return ;
223+
224+ InterviewSession session = answer .getInterviewQuestion ().getInterviewSession ();
225+ session .fail ();
226+ sessionRepository .save (session );
227+
228+ sseEmitterManager .send (session .getId (), "analysis-failed" , Map .of ("message" , message ));
229+ sseEmitterManager .complete (session .getId ());
172230 }
173231
174232 private void deleteTempFile (Path videoPath ) {
@@ -180,15 +238,16 @@ private void deleteTempFile(Path videoPath) {
180238 }
181239 }
182240
183- private void sendFailureToSession (UUID answerId , String message ) {
184- InterviewAnswer answer = answerRepository .findByIdWithQuestionAndSession (answerId ).orElse (null );
185- if (answer != null && answer .getInterviewQuestion ().getInterviewSession () != null ) {
186- InterviewSession session = answer .getInterviewQuestion ().getInterviewSession ();
187- session .fail ();
188- sessionRepository .save (session );
241+ private record AnalysisFeedbacks (
242+ InterviewFeedback stt ,
243+ InterviewFeedback video
244+ ) {
245+ }
189246
190- sseEmitterManager .send (session .getId (), "analysis-failed" , Map .of ("message" , message ));
191- sseEmitterManager .complete (session .getId ());
192- }
247+ private record FinalFeedbackData (
248+ String promptInput ,
249+ List <FinalFeedbackResponse .QuestionFeedback > questionFeedbacks ,
250+ int finalScore
251+ ) {
193252 }
194- }
253+ }
0 commit comments