99import com .back .domain .scenario .repository .SceneTypeRepository ;
1010import com .back .global .ai .dto .result .BaseScenarioResult ;
1111import com .back .global .ai .dto .result .DecisionScenarioResult ;
12+ import com .back .global .ai .exception .AiParsingException ;
1213import com .back .global .ai .service .AiService ;
1314import com .back .global .exception .ApiException ;
1415import com .back .global .exception .ErrorCode ;
@@ -44,6 +45,7 @@ public class ScenarioTransactionService {
4445 private final BaseLineRepository baseLineRepository ;
4546 private final AiService aiService ;
4647 private final ObjectMapper objectMapper ;
48+ private final com .back .global .ai .config .ImageAiConfig imageAiConfig ;
4749
4850 // 상태 업데이트 전용 트랜잭션 메서드
4951 @ Transactional (propagation = Propagation .REQUIRES_NEW )
@@ -138,7 +140,7 @@ private void handleImageGeneration(Scenario scenario, String imagePrompt) {
138140 try {
139141 if (imagePrompt != null && !imagePrompt .trim ().isEmpty ()) {
140142 String imageUrl = aiService .generateImage (imagePrompt )
141- .orTimeout (60 , java .util .concurrent .TimeUnit .SECONDS )
143+ .orTimeout (imageAiConfig . getTimeoutSeconds () , java .util .concurrent .TimeUnit .SECONDS )
142144 .exceptionally (ex -> {
143145 log .warn ("Image generation timeout or error for scenario {}: {}" ,
144146 scenario .getId (), ex .getMessage ());
@@ -164,24 +166,30 @@ private void handleImageGeneration(Scenario scenario, String imagePrompt) {
164166 }
165167
166168 private int calculateTotalScore (Map <Type , Integer > indicatorScores ) {
169+ if (indicatorScores == null || indicatorScores .isEmpty ()) {
170+ log .warn ("indicatorScores is null or empty, returning 0" );
171+ return 0 ;
172+ }
167173 return indicatorScores .values ().stream ()
168174 .mapToInt (Integer ::intValue )
169175 .sum ();
170176 }
171177
172178 private void createBaseSceneTypes (Scenario scenario , BaseScenarioResult aiResult ) {
173- List <SceneType > sceneTypes = aiResult .indicatorScores ()
174- .entrySet ().stream ()
175- .map (entry -> {
176- Type type = entry .getKey ();
177- int point = entry .getValue ();
178- String analysis = aiResult .indicatorAnalysis ().get (type );
179+ if (aiResult .indicators () == null || aiResult .indicators ().isEmpty ()) {
180+ log .warn ("No indicator scores available for scenario {}" , scenario .getId ());
181+ return ;
182+ }
183+
184+ List <SceneType > sceneTypes = aiResult .indicators ().stream ()
185+ .map (indicator -> {
186+ Type type = Type .valueOf (indicator .type ());
179187
180188 return com .back .domain .scenario .entity .SceneType .builder ()
181189 .scenario (scenario )
182190 .type (type )
183- .point (point ) // AI가 분석한 실제 점수
184- .analysis (analysis != null ? analysis : "현재 " + type .name () + " 상황 분석" )
191+ .point (indicator . point () ) // AI가 분석한 실제 점수
192+ .analysis (indicator . analysis () != null ? indicator . analysis () : "현재 " + type .name () + " 상황 분석" )
185193 .build ();
186194 })
187195 .toList ();
@@ -190,18 +198,19 @@ private void createBaseSceneTypes(Scenario scenario, BaseScenarioResult aiResult
190198 }
191199
192200 private void createDecisionSceneTypes (Scenario scenario , DecisionScenarioResult aiResult ) {
193- List <com .back .domain .scenario .entity .SceneType > sceneTypes = aiResult .indicatorScores ()
194- .entrySet ().stream ()
195- .map (entry -> {
196- Type type = entry .getKey ();
197- int point = entry .getValue ();
198- String analysis = aiResult .indicatorAnalysis ().get (type );
201+ if (aiResult .indicators () == null || aiResult .indicators ().isEmpty ()) {
202+ throw new AiParsingException ("Indicator scores are missing in AI response for scenario " + scenario .getId ());
203+ }
204+
205+ List <com .back .domain .scenario .entity .SceneType > sceneTypes = aiResult .indicators ().stream ()
206+ .map (indicator -> {
207+ Type type = Type .valueOf (indicator .type ());
199208
200209 return com .back .domain .scenario .entity .SceneType .builder ()
201210 .scenario (scenario )
202211 .type (type )
203- .point (point )
204- .analysis (analysis != null ? analysis : "분석 정보를 가져올 수 없습니다." )
212+ .point (indicator . point () )
213+ .analysis (indicator . analysis () != null ? indicator . analysis () : "분석 정보를 가져올 수 없습니다." )
205214 .build ();
206215 })
207216 .toList ();
@@ -210,10 +219,12 @@ private void createDecisionSceneTypes(Scenario scenario, DecisionScenarioResult
210219 }
211220
212221 private void createSceneCompare (Scenario scenario , DecisionScenarioResult aiResult ) {
213- List <SceneCompare > compares = aiResult .comparisonResults ()
214- .entrySet ().stream ()
215- .map (entry -> {
216- String resultTypeStr = entry .getKey ().toUpperCase ();
222+ if (aiResult .comparisons () == null || aiResult .comparisons ().isEmpty ()) {
223+ throw new AiParsingException ("Comparison results are missing in AI response for scenario " + scenario .getId ());
224+ }
225+ List <SceneCompare > compares = aiResult .comparisons ().stream ()
226+ .map (comparison -> {
227+ String resultTypeStr = comparison .type ().toUpperCase ();
217228 com .back .domain .scenario .entity .SceneCompareResultType resultType ;
218229 try {
219230 resultType = com .back .domain .scenario .entity .SceneCompareResultType .valueOf (resultTypeStr );
@@ -225,7 +236,7 @@ private void createSceneCompare(Scenario scenario, DecisionScenarioResult aiResu
225236 return SceneCompare .builder ()
226237 .scenario (scenario )
227238 .resultType (resultType )
228- .compareResult (entry . getValue ())
239+ .compareResult (comparison . analysis ())
229240 .build ();
230241 })
231242 .toList ();
@@ -240,4 +251,21 @@ private void updateBaseLineTitle(BaseLine baseLine, String baselineTitle) {
240251 log .info ("BaseLine title updated for ID: {}" , baseLine .getId ());
241252 }
242253 }
254+
255+ @ Transactional (readOnly = true )
256+ public Scenario prepareScenarioData (Long scenarioId ) {
257+ // MultipleBagFetchException을 피하기 위해 별도 쿼리로 각 컬렉션을 초기화
258+ // 1. DecisionNodes 초기화
259+ Scenario scenario = scenarioRepository .findById (scenarioId )
260+ .orElseThrow (() -> new ApiException (ErrorCode .SCENARIO_NOT_FOUND ));
261+ scenario .getDecisionLine ().getDecisionNodes ().size (); // 프록시 초기화
262+
263+ // 2. BaseNodes 초기화
264+ scenario .getBaseLine ().getBaseNodes ().size (); // 프록시 초기화
265+
266+ // 3. User 엔티티 초기화 (새로운 오류 방지)
267+ scenario .getUser ().getMbti (); // User 프록시 초기화
268+
269+ return scenario ;
270+ }
243271}
0 commit comments