diff --git a/Backend_Config b/Backend_Config index 960f98c..c9e90a3 160000 --- a/Backend_Config +++ b/Backend_Config @@ -1 +1 @@ -Subproject commit 960f98c2361ce04653eca80622402539235416f3 +Subproject commit c9e90a3d713c885ee203fa7a939541c42ff59362 diff --git a/src/main/java/com/going/server/domain/chatbot/controller/ChatbotController.java b/src/main/java/com/going/server/domain/chatbot/controller/ChatbotController.java index da36039..f48f0dc 100644 --- a/src/main/java/com/going/server/domain/chatbot/controller/ChatbotController.java +++ b/src/main/java/com/going/server/domain/chatbot/controller/ChatbotController.java @@ -20,7 +20,6 @@ public class ChatbotController { private final ChatbotService chatbotService; - // 지금 챗봇 생성 컨트롤러 만드는 중이었음 @PostMapping("/{graphId}") @Operation(summary = "[챗봇 화면] 챗봇 응답 생성", description = "챗봇 화면에서 사용자의 질문에 응답을 생성합니다.") @ApiResponses( diff --git a/src/main/java/com/going/server/domain/openai/dto/ImageCreateRequestDto.java b/src/main/java/com/going/server/domain/openai/dto/ImageCreateRequestDto.java new file mode 100644 index 0000000..89d07c5 --- /dev/null +++ b/src/main/java/com/going/server/domain/openai/dto/ImageCreateRequestDto.java @@ -0,0 +1,22 @@ +package com.going.server.domain.openai.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ImageCreateRequestDto { + private String prompt; + private String model = "dall-e-3"; + private String style = "vivid"; + private String size = "1024x1024"; + private int n = 1; + + public ImageCreateRequestDto(String prompt) { + this.prompt = prompt; + } +} diff --git a/src/main/java/com/going/server/domain/openai/dto/ImageCreateResponseDto.java b/src/main/java/com/going/server/domain/openai/dto/ImageCreateResponseDto.java new file mode 100644 index 0000000..9d8dfcb --- /dev/null +++ b/src/main/java/com/going/server/domain/openai/dto/ImageCreateResponseDto.java @@ -0,0 +1,22 @@ +package com.going.server.domain.openai.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class ImageCreateResponseDto { + private List data; + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class Data { + private String url; + private String revised_prompt; + } +} \ No newline at end of file diff --git a/src/main/java/com/going/server/domain/openai/service/ImageCreateService.java b/src/main/java/com/going/server/domain/openai/service/ImageCreateService.java index 7767091..d507b5e 100644 --- a/src/main/java/com/going/server/domain/openai/service/ImageCreateService.java +++ b/src/main/java/com/going/server/domain/openai/service/ImageCreateService.java @@ -1,26 +1,42 @@ package com.going.server.domain.openai.service; -import com.theokanning.openai.image.CreateImageRequest; -import com.theokanning.openai.OpenAiService; -import jakarta.annotation.Resource; +import com.going.server.domain.openai.dto.ImageCreateRequestDto; +import com.going.server.domain.openai.dto.ImageCreateResponseDto; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.*; import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; @Service -@RequiredArgsConstructor public class ImageCreateService { - @Resource(name = "getOpenAIService") - private final OpenAiService openAiService; + private final RestTemplate restTemplate = new RestTemplate(); + private final String openAIImageUrl; + private final String apiKey; - public String generatePicture(String prompt) { - CreateImageRequest createImageRequest = CreateImageRequest.builder() - .prompt(prompt) - .size("512x512") //사이즈 - .n(1) - .build(); + public ImageCreateService( + @Qualifier("openAIImageUrl") String openAIImageUrl, + @Qualifier("openAIKey") String apiKey + ) { + this.openAIImageUrl = openAIImageUrl; + this.apiKey = apiKey; + } + + public String generatePicture(ImageCreateRequestDto requestDto) { + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(apiKey); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity entity = new HttpEntity<>(requestDto, headers); + + ResponseEntity response = restTemplate.exchange( + openAIImageUrl, + HttpMethod.POST, + entity, + ImageCreateResponseDto.class + ); - //URL로 리턴 (1시간 후 만료) - return openAiService.createImage(createImageRequest).getData().get(0).getUrl(); + return response.getBody().getData().get(0).getUrl(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/going/server/domain/quiz/generate/PictureQuizGenerator.java b/src/main/java/com/going/server/domain/quiz/generate/PictureQuizGenerator.java index 77b5f24..38236be 100644 --- a/src/main/java/com/going/server/domain/quiz/generate/PictureQuizGenerator.java +++ b/src/main/java/com/going/server/domain/quiz/generate/PictureQuizGenerator.java @@ -2,6 +2,7 @@ import com.going.server.domain.graph.entity.Graph; import com.going.server.domain.graph.entity.GraphNode; +import com.going.server.domain.openai.dto.ImageCreateRequestDto; import com.going.server.domain.openai.service.ImageCreateService; import com.going.server.domain.quiz.dto.PictureQuizDto; import lombok.AllArgsConstructor; @@ -58,8 +59,9 @@ public PictureQuizDto generate(Graph graph) { int answerIndex = random.nextInt(shuffledListSize); String answer = new ArrayList<>(selectedSentences).get(answerIndex); - String prompt = buildImagePrompt(answer); - String imageUrl = imageCreateService.generatePicture(prompt); + String prompt = buildQuizImagePrompt(answer); + ImageCreateRequestDto requestDto = new ImageCreateRequestDto(prompt); + String imageUrl = imageCreateService.generatePicture(requestDto); return PictureQuizDto.builder() .imageUrl(imageUrl) @@ -69,9 +71,54 @@ public PictureQuizDto generate(Graph graph) { } // 이미지 생성 프롬프트 생성 메서드 - private String buildImagePrompt(String answer) { - return "아래 설명을 이미지로 표현해주세요.\n\n" - + "[설명]\n" + answer; + + // 버전1 +// private String buildQuizImagePrompt(String answer) { +// return "You are given an educational description in natural language.\n\n" + +// "1. First, analyze the sentence to determine what kind of relationship it contains, such as:\n" + +// "- Cause and effect\n" + +// "- Inclusion or category\n" + +// "- Example and concept\n" + +// "- Behavioral actions\n" + +// "- General explanation\n\n" + +// "2. Then, generate a **cute, warm, and educational diagram-style illustration** that reflects the structure and meaning of the sentence.\n\n" + +// "Use **flat vector illustrations inspired by iOS emojis**, with **bright and soft colors**.\n" + +// "If the sentence includes multiple ideas, arrange the illustration using diagrams, arrows, or symbolic layouts that match the logical structure.\n" + +// "Do **not include any text or labels** in the image. Use only visuals.\n\n" + +// "[Description]\n" + answer; +// } + + // 버전2 +// public String buildQuizImagePrompt(String answer) { +// return "You are given an educational description in natural language.\n\n" + +// "1. First, analyze the sentence to determine what kind of relationship it contains, such as:\n" + +// "- Cause and effect\n" + +// "- Inclusion or category\n" + +// "- Example and concept\n" + +// "- Behavioral actions\n" + +// "- General explanation\n\n" + +// "2. Then, generate a cute, warm, and educational diagram-style illustration that reflects the structure and meaning of the sentence.\n\n" + +// "Use flat vector illustrations inspired by iOS emojis, with bright and soft colors.\n" + +// "If the sentence includes multiple ideas, arrange the illustration using symbols or visual layouts like arrows, sets, or diagrams **only when necessary to express the logical relationship**.\n" + +// "Do not include any text or labels in the image. Use only visuals.\n\n" + +// "[Description]\n" + answer; +// } + + // 버전3 + public static String buildQuizImagePrompt(String answer) { + return "You are given an educational description in natural language.\n\n" + + "1. First, analyze the sentence to determine what kind of relationship it contains, such as:\n" + + "- Cause and effect\n" + + "- Inclusion or category\n" + + "- Example and concept\n" + + "- Behavioral actions\n" + + "- General explanation\n\n" + + "2. Then, generate a cute, warm, and educational diagram-style illustration that reflects the structure and meaning of the sentence.\n\n" + + "Use flat vector illustrations inspired by iOS emojis, with bright and soft colors.\n\n" + + "If the sentence includes multiple ideas or relationships, use simple visual symbols like arrows or grouping layouts to represent those relationships **only when necessary**.\n" + + "Do **not overuse symbols**—use them only when they help express meaning clearly.\n\n" + + "Do not include any text or labels in the image. Use only visuals.\n\n" + + "[Description]\n" + answer; } } diff --git a/src/main/java/com/going/server/global/config/OpenAIConfig.java b/src/main/java/com/going/server/global/config/OpenAIConfig.java index 7e31345..284bcc2 100644 --- a/src/main/java/com/going/server/global/config/OpenAIConfig.java +++ b/src/main/java/com/going/server/global/config/OpenAIConfig.java @@ -1,19 +1,36 @@ package com.going.server.global.config; -import org.springframework.context.annotation.Configuration; import com.theokanning.openai.OpenAiService; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import java.time.Duration; @Configuration public class OpenAIConfig { + @Value("${openai.key}") private String apiKey; + @Value("${openai.image-url}") + private String imageUrl; + + @Value("${openai.timeout:30}") + private int timeout; + @Bean public OpenAiService getOpenAIService() { - return new OpenAiService(apiKey, Duration.ofSeconds(30)); + return new OpenAiService(apiKey, Duration.ofSeconds(timeout)); + } + + @Bean(name = "openAIImageUrl") + public String openAIImageUrl() { + return imageUrl; + } + + @Bean(name = "openAIKey") + public String openAIKey() { + return apiKey; } }