22
33import com .going .server .domain .graph .entity .Graph ;
44import com .going .server .domain .graph .entity .GraphNode ;
5+ import com .going .server .domain .graph .repository .GraphRepository ;
56import com .going .server .domain .openai .dto .ImageCreateRequestDto ;
67import com .going .server .domain .openai .service .ImageCreateService ;
78import com .going .server .domain .quiz .dto .PictureQuizDto ;
1415@ AllArgsConstructor
1516public class PictureQuizGenerator implements QuizGenerator <PictureQuizDto > {
1617 private final ImageCreateService imageCreateService ;
18+ private final GraphRepository graphRepository ;
1719
1820 @ Override
19- public PictureQuizDto generate (Graph graph ) {
21+ public PictureQuizDto generate (Graph currentGraph ) {
2022 Random random = new Random ();
21- // Set<String> shuffled = new HashSet<>(); // 보기로 제공할 랜덤 문장들(중복 방지)
22- int shuffledListSize = 3 ; // 총 보기 수 (정답 포함)
23- List <String > candidateSentences = new ArrayList <>(); // 전처리한 includeSentence
23+ int shuffledListSize = 3 ;
2424
25- // 그래프 노드를 돌면서 문장 후보 수집
26- for (GraphNode node : graph .getNodes ()) {
27- // IncludeSentence가 비어있는 경우 넘어가기
28- if (node .getIncludeSentence () == null || node .getIncludeSentence ().isBlank ()) continue ;
25+ // 정답 후보 문장: 현재 그래프에서 수집
26+ List <String > answerCandidates = extractCandidateSentences (currentGraph );
2927
30- // "." 으로 문장 나누기
31- String [] splitSentences = node .getIncludeSentence ().split ("\\ ." );
28+ if (answerCandidates .isEmpty ()) {
29+ throw new IllegalStateException ("현재 그래프에서 사용할 수 있는 문장이 없습니다." );
30+ }
3231
33- for (String rawSentence : splitSentences ) {
34- String sentence = rawSentence .trim ();
35- if (sentence .isBlank ()) continue ; // 공백은 스킵
36- if (sentence .split ("\\ s+" ).length < 5 ) continue ; // 5단어 미만은 스킵
32+ // 정답 1개 선택
33+ Collections .shuffle (answerCandidates , random );
34+ String answer = answerCandidates .get (0 );
3735
38- candidateSentences .add (sentence );
36+ // 오답 후보 문장: 다른 그래프들에서 수집
37+ List <Graph > allGraphs = graphRepository .findAll ();
38+ List <String > distractorCandidates = new ArrayList <>();
39+ for (Graph graph : allGraphs ) {
40+ if (!graph .equals (currentGraph )) {
41+ distractorCandidates .addAll (extractCandidateSentences (graph ));
3942 }
4043 }
4144
42- // 후보 문장이 부족할 경우 방어
43- if (candidateSentences .size () < shuffledListSize ) {
44- throw new IllegalStateException ( "생성 가능한 문장이 부족합니다." );
45+ // 오답이 부족한 경우: 현재 그래프에서 추가 확보
46+ if (distractorCandidates .size () < shuffledListSize - 1 ) {
47+ distractorCandidates . addAll ( answerCandidates . subList ( 1 , Math . min ( answerCandidates . size (), shuffledListSize )) );
4548 }
4649
47- // 랜덤으로 문장 선택
48- Collections .shuffle (candidateSentences , random );
49-
50- // 보기용 문장 추가
50+ // 선지 셔플 및 정답 포함해서 뽑기
51+ Collections .shuffle (distractorCandidates , random );
5152 Set <String > selectedSentences = new LinkedHashSet <>();
53+ selectedSentences .add (answer );
5254 int index = 0 ;
53- while (selectedSentences .size () < shuffledListSize && index < candidateSentences .size ()) {
54- selectedSentences .add (candidateSentences .get (index ));
55+ while (selectedSentences .size () < shuffledListSize && index < distractorCandidates .size ()) {
56+ selectedSentences .add (distractorCandidates .get (index ));
5557 index ++;
5658 }
5759
58- // 무작위로 정답 보기 설정
59- int answerIndex = random . nextInt ( shuffledListSize );
60- String answer = new ArrayList <>( selectedSentences ). get ( answerIndex );
60+ if ( selectedSentences . size () < shuffledListSize ) {
61+ throw new IllegalStateException ( "문제가 될 문장이 충분하지 않습니다." );
62+ }
6163
6264 String prompt = buildQuizImagePrompt (answer );
6365 ImageCreateRequestDto requestDto = new ImageCreateRequestDto (
@@ -66,7 +68,8 @@ public PictureQuizDto generate(Graph graph) {
6668 "vivid" ,
6769 "standard" ,
6870 "1024x1024" ,
69- 1 );
71+ 1
72+ );
7073 String imageUrl = imageCreateService .generatePicture (requestDto );
7174
7275 return PictureQuizDto .builder ()
@@ -76,6 +79,26 @@ public PictureQuizDto generate(Graph graph) {
7679 .build ();
7780 }
7881
82+ // 문장 후보 추출 메서드 분리
83+ private List <String > extractCandidateSentences (Graph graph ) {
84+ List <String > sentences = new ArrayList <>();
85+
86+ for (GraphNode node : graph .getNodes ()) {
87+ String raw = node .getIncludeSentence ();
88+ if (raw == null || raw .isBlank ()) continue ;
89+
90+ String [] split = raw .split ("\\ ." );
91+ for (String s : split ) {
92+ String trimmed = s .trim ();
93+ if (trimmed .isBlank ()) continue ;
94+ if (trimmed .split ("\\ s+" ).length < 5 ) continue ;
95+ sentences .add (trimmed );
96+ }
97+ }
98+
99+ return sentences ;
100+ }
101+
79102 // 이미지 생성 프롬프트 생성 메서드
80103 public static String buildQuizImagePrompt (String answer ) {
81104 return "You are given an educational description in natural language.\n \n " +
0 commit comments