diff --git a/src/main/java/io/github/petty/pipeline/controller/PipelineController.java b/src/main/java/io/github/petty/pipeline/controller/PipelineController.java index 7ca4f4a..a239e7c 100644 --- a/src/main/java/io/github/petty/pipeline/controller/PipelineController.java +++ b/src/main/java/io/github/petty/pipeline/controller/PipelineController.java @@ -40,6 +40,7 @@ public String processPipeline( // 실제 VisionServiceImpl 에서 사용하는 요소 @RequestParam("file") MultipartFile file, @RequestParam("petName") String pet, + @RequestParam("info") String info, Model model ) { @@ -47,7 +48,7 @@ public String processPipeline( // String prompt = togetherPromptBuilder.buildPrompt(visionReport, location); String visionReport = visionService.analyze(file, pet); - String jsonPrompt = togetherPromptBuilder.buildPrompt(visionReport, location); + String jsonPrompt = togetherPromptBuilder.buildPrompt(visionReport, location, info); log.info(jsonPrompt); ObjectMapper objectMapper = new ObjectMapper(); diff --git a/src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java b/src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java index 7d1a82a..1e258b2 100644 --- a/src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java +++ b/src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java @@ -14,11 +14,12 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import jakarta.servlet.http.HttpSession; import java.util.Map; @Slf4j @Controller -@RequestMapping("/flow") // 기존 controller들과 충돌 방지 +@RequestMapping("/flow") @RequiredArgsConstructor public class UnifiedFlowController { @@ -36,34 +37,51 @@ public String page() { public String analyze( @RequestParam("file") MultipartFile file, @RequestParam("petName") String petName, - @RequestParam("location") String location, - Model model + Model model, + HttpSession session ) { try { - // 1. 중간 종 추론 결과 String interim = visionUseCase.interim(file.getBytes(), petName); - - // 2. Vision 보고서 생성 String visionReport = visionService.analyze(file, petName); - log.info("📄 Vision Report: {}", visionReport); - log.info("📌 location = {}", location); - - // 3. 프롬프트 생성 및 추천 요청 - String jsonPrompt = togetherPromptBuilder.buildPrompt(visionReport, location); - log.info("📌 location = {}", location); - Map promptMapper = new ObjectMapper().readValue(jsonPrompt, new TypeReference<>() {}); - RecommendResponseDTO recommendation = recommendService.recommend(promptMapper); - // 4. 화면에 전달 model.addAttribute("interim", interim); model.addAttribute("visionReport", visionReport); - model.addAttribute("recommendation", recommendation); + model.addAttribute("petName", petName); + session.setAttribute("visionReport", visionReport); } catch (Exception e) { - log.error("❌ 분석 중 오류 발생", e); - model.addAttribute("error", "분석 및 추천 중 오류가 발생했습니다."); + log.error("❌ interim 분석 중 오류", e); + model.addAttribute("error", "중간 분석 중 오류 발생"); } + return "unifiedFlow"; + } + @PostMapping("/report") + public String report( + @RequestParam("petName") String petName, + @RequestParam("location") String location, + @RequestParam("info") String info, + Model model, + HttpSession session + ) { + try { + String visionReport = (String) session.getAttribute("visionReport"); + if (visionReport == null) { + model.addAttribute("error", "세션에 Vision 보고서가 없습니다. 다시 분석을 시작해 주세요."); + return "unifiedFlow"; + } + + String jsonPrompt = togetherPromptBuilder.buildPrompt(visionReport, location, info); + Map promptMapper = new ObjectMapper().readValue(jsonPrompt, new TypeReference<>() {}); + RecommendResponseDTO recommendation = recommendService.recommend(promptMapper); + + model.addAttribute("visionReport", visionReport); // 다시 보여주기 위해 필요 + model.addAttribute("recommendation", recommendation); + model.addAttribute("petName", petName); + } catch (Exception e) { + log.error("❌ 추천 생성 중 오류", e); + model.addAttribute("error", "추천 생성 중 오류 발생"); + } return "unifiedFlow"; } } diff --git a/src/main/java/io/github/petty/pipeline/service/PromptGeneratorService.java b/src/main/java/io/github/petty/pipeline/service/PromptGeneratorService.java index 65f2fae..981c13c 100644 --- a/src/main/java/io/github/petty/pipeline/service/PromptGeneratorService.java +++ b/src/main/java/io/github/petty/pipeline/service/PromptGeneratorService.java @@ -3,5 +3,5 @@ import com.fasterxml.jackson.core.JsonProcessingException; public interface PromptGeneratorService { - String generatePrompt(String extractedPetInfoJson, String location) throws JsonProcessingException; + String generatePrompt(String extractedPetInfoJson, String location, String info) throws JsonProcessingException; } diff --git a/src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java b/src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java index 59f0a6f..058e9b3 100644 --- a/src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java +++ b/src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java @@ -15,13 +15,19 @@ public class PromptGeneratorServiceImpl implements PromptGeneratorService { ObjectMapper mapper = new ObjectMapper(); @Override - public String generatePrompt(String extractedPetInfoJson, String location) throws JsonProcessingException { + public String generatePrompt(String extractedPetInfoJson, String location, String info) throws JsonProcessingException { + // 필수 정보 예외 if (extractedPetInfoJson.isEmpty()) { throw new IllegalArgumentException("에러! 필수 정보가 없습니다."); } else if (location.isEmpty()) { throw new IllegalArgumentException("에러! 사용자 위치 정보가 없습니다."); } + // 추가 정보 : 비어도 상관 없음 + if (info.isEmpty()) { + info = "입력된 추가 요청 사항 없음"; + } + // 기본 문자열 String petInfoString = """ { @@ -32,17 +38,12 @@ public String generatePrompt(String extractedPetInfoJson, String location) throw Map petInfoMap = mapper.readValue(petInfoString, new TypeReference<>() {}); // location 항목 추가 petInfoMap.put("location", "%s".formatted(location)); + // info 항목 추가 + petInfoMap.put("info", "%s".formatted(info)); // JSON 문자열로 변환 String finalString = mapper.writeValueAsString(petInfoMap); log.info(finalString); return finalString; - -// return String.format(""" -// { -// %s, -// "location": "%s" -// } -// """, extractedPetInfoJson, location); } } diff --git a/src/main/java/io/github/petty/pipeline/support/TogetherPromptBuilder.java b/src/main/java/io/github/petty/pipeline/support/TogetherPromptBuilder.java index 3aff791..665b69f 100644 --- a/src/main/java/io/github/petty/pipeline/support/TogetherPromptBuilder.java +++ b/src/main/java/io/github/petty/pipeline/support/TogetherPromptBuilder.java @@ -15,7 +15,7 @@ public class TogetherPromptBuilder { private final TogetherService togetherService; private final PromptGeneratorService promptGeneratorService; - public String buildPrompt(String visionReport, String location) throws Exception { + public String buildPrompt(String visionReport, String location, String info) throws Exception { try { if (visionReport.isEmpty()) { log.info("Vision API 에서 필수 정보를 받아오지 못했습니다."); @@ -23,7 +23,7 @@ public String buildPrompt(String visionReport, String location) throws Exception } String extractedPetInfoJson = togetherService.answer( visionReport + " -> 이 문장에서 반려동물의 이름(name), 종(species), 무게(weight), 맹수 여부(is_danger(only true or false))를 JSON 형식으로 작성 + " + - "만약 반려동물의 종과 무게를 보았을 때, 입마개가 필요할 것 같다면 맹수 여부를 'true'로 작성 + " + "고양이는 맹수 여부를 false로 작성 " + + "만약 반려동물의 종과 무게를 보았을 때, 사람을 물어 중상을 입히거나 사망에 이르게 할 수 있는 경우 맹수 여부를 'true'로 작성 + " + "고양이는 맹수 여부를 false로 작성 " + "무게는 kg 단위를 반드시 포함 " + "no markdown " + "-> 양식에 맞춰서 작성 " + """ "name": "???", "species": "???", @@ -31,7 +31,7 @@ public String buildPrompt(String visionReport, String location) throws Exception "is_danger": "???" """ + " -> 부가 설명이나 그 어떠한 텍스트 없이 양식의 빈 항목을 채워서 답변할 것." ); - return promptGeneratorService.generatePrompt(extractedPetInfoJson, location); + return promptGeneratorService.generatePrompt(extractedPetInfoJson, location, info); } catch (RuntimeException e) { log.info("TogetherPromptBuilder 내부 오류."); diff --git a/src/main/resources/templates/unifiedFlow.html b/src/main/resources/templates/unifiedFlow.html index 85dadac..66c1911 100644 --- a/src/main/resources/templates/unifiedFlow.html +++ b/src/main/resources/templates/unifiedFlow.html @@ -7,18 +7,16 @@ body { font-family: Arial; margin: 40px; background: #f4f4f4; } form, .result-block { background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 30px; } input[type=text], input[type=file] { width: 100%; padding: 10px; margin-top: 10px; border-radius: 5px; border: 1px solid #ccc; } - input[type=submit] { padding: 10px 20px; background: #007BFF; color: #fff; border-radius: 5px; cursor: pointer; border: none; } - input[type=submit]:hover { background: #0056b3; } + input[type=submit], button { padding: 10px 20px; background: #007BFF; color: #fff; border-radius: 5px; cursor: pointer; border: none; } + input[type=submit]:hover, button:hover { background: #0056b3; } pre { background: #eee; padding: 10px; border-radius: 5px; overflow-x: auto; } - .dropdown { position: relative; } - .dropdown-list { display: none; position: absolute; top: 100%; width: 100%; max-height: 200px; overflow-y: auto; background: #fff; border: 1px solid #ccc; z-index: 100; } - .dropdown-list li { padding: 8px; cursor: pointer; } .dropdown-list li:hover { background-color: #f0f0f0; }

🐾 반려동물 여행지 추천

+
@@ -26,30 +24,41 @@

🐾 반려동물 여행지 추천

- - - - +
-
+ +

중간 분석 결과


 
-
+ +

최종 Vision 분석 보고서


+  
+ + + +
+ +
+ + + + + +
-
+ +

추천 여행지


 
+

오류 발생

@@ -57,8 +66,18 @@

오류 발생