[PIPELINE] 분석, 보고서, 추천 진행 및 결과물 출력#29
Conversation
Summary by CodeRabbit
Walkthrough기존의 파이프라인 및 추천 컨트롤러 로직이 리팩토링되어, 반려동물 이미지 분석과 여행지 추천 절차가 분리되었습니다. 각 단계에서 추가 요청 사항( Changes
Sequence Diagram(s)sequenceDiagram
participant 사용자
participant UnifiedFlowController
participant 세션
participant PromptGeneratorService
participant TogetherPromptBuilder
사용자->>UnifiedFlowController: /analyze (이미지, 반려동물명)
UnifiedFlowController->>세션: visionReport 저장
UnifiedFlowController-->>사용자: 분석 결과 화면 반환
사용자->>UnifiedFlowController: /report (반려동물명, 위치, info)
UnifiedFlowController->>세션: visionReport 조회
UnifiedFlowController->>TogetherPromptBuilder: buildPrompt(visionReport, 위치, info)
TogetherPromptBuilder->>PromptGeneratorService: generatePrompt(visionReport, 위치, info)
TogetherPromptBuilder-->>UnifiedFlowController: 프롬프트 반환
UnifiedFlowController-->>사용자: 추천 결과 화면 반환
Possibly related PRs
Suggested reviewers
Poem
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 30th. To opt out, configure ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
🙋🏻♂️ 코드 리뷰 코멘트1. 컨트롤러 분리 잘 보았습니다!
2. 세션 처리 쪽 확인해봤어요!분석 결과를 3. info 파라미터 활용 👍사용자가 입력한 추가 요청사항을 info로 받아서 프롬프트에 포함시키는 거 신기했습니다. 이게 비어 있을 때 기본 메시지로 처리하는 부분도 잘 챙기신 것 같습니다! 4. 프론트 부분도 잘 정리되어 있네요HTML에 info 입력 필드랑 지역 드롭다운 개선된 부분 잘 봤습니다. 직접 돌려보면서 확인해보면 더 좋을 것 같습니다. JS는 제가 아직 익숙하진 않지만 구조가 깔끔해서 흐름은 이해하기 쉬웠습니다. 요약 리뷰이번 PR은 흐름 정리가 잘 되어 있어서 보기 편했고, 코드도 깔끔했습니다. 기능 분리나 사용자 요청 반영 같은 게 실제 서비스에서도 중요하다고 들었는데, 그 방향으로 잘 잡혀 있어서 많이 배웠습니다 🙇🏻♂️ 혹시 제가 잘못 이해한 부분 있으면 편하게 말씀해주세요! |
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java (1)
1-50: 코드 품질 개선을 위한 제안오류 메시지와 기본값을 상수로 정의하면 코드의 가독성과 유지보수성을 더욱 향상시킬 수 있습니다. 예를 들어:
+private static final String ERROR_MISSING_INFO = "에러! 필수 정보가 없습니다."; +private static final String ERROR_MISSING_LOCATION = "에러! 사용자 위치 정보가 없습니다."; +private static final String DEFAULT_INFO = "입력된 추가 요청 사항 없음"; @Override public String generatePrompt(String extractedPetInfoJson, String location, String info) throws JsonProcessingException { // 필수 정보 예외 if (extractedPetInfoJson.isEmpty()) { - throw new IllegalArgumentException("에러! 필수 정보가 없습니다."); + throw new IllegalArgumentException(ERROR_MISSING_INFO); } else if (location.isEmpty()) { - throw new IllegalArgumentException("에러! 사용자 위치 정보가 없습니다."); + throw new IllegalArgumentException(ERROR_MISSING_LOCATION); } // 추가 정보 : 비어도 상관 없음 if (info.isEmpty()) { - info = "입력된 추가 요청 사항 없음"; + info = DEFAULT_INFO; }이렇게 하면 향후 메시지 변경이 필요할 때 한 곳에서만 수정하면 되므로 유지보수가 더 쉬워집니다.
src/main/resources/templates/unifiedFlow.html (1)
43-50: 접근성 및 보안(자동완성) 개선 제안
label-for매핑은 좋지만, 스크린리더 사용자를 위해aria-label또는placeholder를 보다 설명적으로 작성하면 접근성이 향상됩니다.- 지역 목록이 클라이언트에 그대로 노출되므로, JS 파일 분리 또는 서버 사이드 검색 API로 전환 시 초기 로딩 성능을 개선할 수 있습니다.
(선택 사항)
<datalist>요소를 활용하면 JS 없는 환경에서도 기본 자동완성 기능을 제공할 수 있습니다.src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java (2)
51-52:petName역시 세션에 저장하여 일관성 확보 권장
/report단계에서 클라이언트가 숨겨진 필드를 조작하면 다른 애완동물 이름으로 추천을 요청할 수 있습니다.
petName을 세션에 함께 저장하거나, 애초에 세션 기반 도메인 객체(예:FlowContext)를 만들어 상태를 캡슐화하면 변조 위험을 줄일 수 있습니다.
68-72: 세션 만료 시 UX 향상 방안 제안현재 세션에
visionReport가 없으면 단순 오류 메시지를 표시합니다.
분석 폼으로 자동 리다이렉트하거나, 버튼으로 “다시 분석하기” 액션을 제공하면 사용자가 흐름을 이해하기 쉽습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/main/java/io/github/petty/pipeline/controller/PipelineController.java(1 hunks)src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java(2 hunks)src/main/java/io/github/petty/pipeline/service/PromptGeneratorService.java(1 hunks)src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java(2 hunks)src/main/java/io/github/petty/pipeline/support/TogetherPromptBuilder.java(1 hunks)src/main/resources/templates/unifiedFlow.html(3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java (1)
src/main/java/io/github/petty/pipeline/controller/PipelineController.java (1)
Slf4j(20-67)
🔇 Additional comments (10)
src/main/java/io/github/petty/pipeline/service/PromptGeneratorService.java (1)
6-6: 인터페이스 메서드 시그니처 업데이트가 적절히 이루어졌습니다.새로운
info매개변수가 추가되어 사용자의 추가 요청 사항을 처리할 수 있게 되었습니다. 이 변경은 컨트롤러와 서비스 구현체의 변경사항과 일관성이 있으며, 모듈화된 흐름 제어에 잘 부합합니다.src/main/java/io/github/petty/pipeline/controller/PipelineController.java (2)
43-43: 새 매개변수 추가가 적절히 이루어졌습니다.사용자로부터 추가 정보(
info)를 받을 수 있도록 요청 매개변수가 추가되었습니다. 이는 프롬프트 생성 프로세스에 더 많은 컨텍스트를 제공하여 추천의 질을 향상시킬 수 있습니다.
51-51: 프롬프트 빌더 메서드 호출이 올바르게 업데이트되었습니다.새로운
info매개변수가buildPrompt메서드 호출에 포함되어 있어 사용자의 추가 요청 사항이 프롬프트 생성 과정에 전달됩니다. 변경된 메서드 시그니처와 일관성이 있습니다.src/main/java/io/github/petty/pipeline/support/TogetherPromptBuilder.java (3)
18-18: 메서드 시그니처 업데이트가 적절히 이루어졌습니다.
buildPrompt메서드에 새로운info매개변수가 추가되어 컨트롤러와 서비스 계층 간의 일관성을 유지합니다. 이는 사용자의 추가 요청 사항을 프롬프트 생성 과정에 반영할 수 있게 합니다.
26-26: 맹수 여부 판단 기준이 개선되었습니다.이전에는 '종과 무게에 따라 입마개가 필요할 수 있는지'를 기준으로 했으나, 이제는 '사람을 물어 중상을 입히거나 사망에 이르게 할 수 있는 경우'로 기준이 변경되었습니다. 이는 보다 명확하고 안전 중심적인 판단 기준으로 개선되었습니다.
34-34: 프롬프트 생성 서비스 호출이 올바르게 업데이트되었습니다.새로운
info매개변수가promptGeneratorService.generatePrompt메서드 호출에 포함되어 있어 사용자의 추가 요청 사항이 최종 프롬프트 생성에 반영됩니다.src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java (4)
18-18: 메서드 시그니처 업데이트가 적절히 이루어졌습니다.인터페이스 선언과 일치하도록
generatePrompt메서드에 새로운info매개변수가 추가되었습니다. 이는 사용자의 추가 요청 사항을 처리할 수 있게 합니다.
19-24: 필수 정보에 대한 유효성 검사가 잘 구현되어 있습니다.
extractedPetInfoJson과location매개변수가 비어있는지 확인하고, 비어있을 경우 적절한 예외를 발생시킵니다. 이는 필수 정보가 누락되었을 때 오류를 명확하게 식별할 수 있게 합니다.
26-29: 추가 정보(info)에 대한 기본값 처리가 적절히 구현되었습니다.
info매개변수가 비어있을 경우 "입력된 추가 요청 사항 없음"이라는 기본값을 설정합니다. 이는 추가 요청 사항이 선택적이면서도 항상 일관된 형식의 데이터가 프롬프트에 포함되도록 보장합니다.
41-42: info 항목이 JSON에 적절히 추가되었습니다.사용자의 추가 요청 사항이 JSON 데이터 구조에 "info" 키로 추가됩니다. 이는 최종 프롬프트에 사용자의 추가 요구사항이 포함되도록 보장합니다.
| const locationInput = document.getElementById('location'); | ||
| const dropdownList = document.createElement('ul'); | ||
| dropdownList.className = 'dropdown-list'; | ||
| dropdownList.style.position = 'absolute'; | ||
| dropdownList.style.width = '100%'; | ||
| dropdownList.style.maxHeight = '200px'; | ||
| dropdownList.style.overflowY = 'auto'; | ||
| dropdownList.style.backgroundColor = '#fff'; | ||
| dropdownList.style.border = '1px solid #ccc'; | ||
| dropdownList.style.zIndex = 100; | ||
| dropdownList.style.display = 'none'; | ||
| locationInput.parentElement.appendChild(dropdownList); | ||
|
|
There was a problem hiding this comment.
locationInput가 존재하지 않는 초기 페이지 진입 시 스크립트 오류 발생 가능성
visionReport가 아직 없는 최초 렌더링 단계에서는 id="location" 인 요소가 DOM 에 존재하지 않습니다.
하지만 스크립트는 DOMContentLoaded 직후 getElementById('location') 결과를 바로 사용 하고 있으며, null 에서 parentElement.appendChild·addEventListener 호출이 일어나면 런타임 JS 오류로 페이지가 비정상 종료됩니다.
간단한 방어 코드로 예방해 주세요.
- const locationInput = document.getElementById('location');
- const dropdownList = document.createElement('ul');
+ const locationInput = document.getElementById('location');
+ if (!locationInput) {
+ // location 입력이 없는 초기 화면에서는 자동완성 스크립트를 건너뜁니다.
+ return;
+ }
+ const dropdownList = document.createElement('ul');📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const locationInput = document.getElementById('location'); | |
| const dropdownList = document.createElement('ul'); | |
| dropdownList.className = 'dropdown-list'; | |
| dropdownList.style.position = 'absolute'; | |
| dropdownList.style.width = '100%'; | |
| dropdownList.style.maxHeight = '200px'; | |
| dropdownList.style.overflowY = 'auto'; | |
| dropdownList.style.backgroundColor = '#fff'; | |
| dropdownList.style.border = '1px solid #ccc'; | |
| dropdownList.style.zIndex = 100; | |
| dropdownList.style.display = 'none'; | |
| locationInput.parentElement.appendChild(dropdownList); | |
| const locationInput = document.getElementById('location'); | |
| if (!locationInput) { | |
| // location 입력이 없는 초기 화면에서는 자동완성 스크립트를 건너뜁니다. | |
| return; | |
| } | |
| const dropdownList = document.createElement('ul'); | |
| dropdownList.className = 'dropdown-list'; | |
| dropdownList.style.position = 'absolute'; | |
| dropdownList.style.width = '100%'; | |
| dropdownList.style.maxHeight = '200px'; | |
| dropdownList.style.overflowY = 'auto'; | |
| dropdownList.style.backgroundColor = '#fff'; | |
| dropdownList.style.border = '1px solid #ccc'; | |
| dropdownList.style.zIndex = 100; | |
| dropdownList.style.display = 'none'; | |
| locationInput.parentElement.appendChild(dropdownList); |
🤖 Prompt for AI Agents
In src/main/resources/templates/unifiedFlow.html around lines 69 to 81, the code
assumes the element with id 'location' exists and directly accesses its
parentElement and adds event listeners, which causes runtime errors if the
element is not present on initial page load. To fix this, add a null check after
getting the element by id 'location' and only proceed with creating and
appending the dropdownList and adding event listeners if the element is not
null, preventing script errors on pages without the 'location' element.
| if (!locationInput.contains(e.target) && !dropdownList.contains(e.target)) { | ||
| dropdownList.style.display = 'none'; | ||
| } | ||
| }); |
There was a problem hiding this comment.
전역 클릭 이벤트에서도 locationInput 존재 여부 확인 필요
위 이슈와 동일하게, 초기 페이지에서 locationInput 이 null 인 경우 contains 호출이 불가합니다. 아래처럼 가드를 추가해 주세요.
- if (!locationInput.contains(e.target) && !dropdownList.contains(e.target)) {
+ if (!locationInput || (!locationInput.contains(e.target) && !dropdownList.contains(e.target))) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!locationInput.contains(e.target) && !dropdownList.contains(e.target)) { | |
| dropdownList.style.display = 'none'; | |
| } | |
| }); | |
| document.addEventListener('click', function(e) { | |
| if (!locationInput || (!locationInput.contains(e.target) && !dropdownList.contains(e.target))) { | |
| dropdownList.style.display = 'none'; | |
| } | |
| }); |
🤖 Prompt for AI Agents
In src/main/resources/templates/unifiedFlow.html around lines 182 to 185, the
code calls contains on locationInput without checking if locationInput is null,
which can cause errors on initial page load. Add a guard condition to verify
locationInput exists before calling contains on it to prevent runtime
exceptions.
| @PostMapping("/report") | ||
| public String report( | ||
| @RequestParam("petName") String petName, | ||
| @RequestParam("location") String location, | ||
| @RequestParam("info") String info, | ||
| Model model, | ||
| HttpSession session | ||
| ) { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
@PostMapping("/report") 파라미터 검증 및 예외 분리 필요
location,petName이 빈 문자열일 때도 그대로 서비스 로직으로 전달됩니다.@NotBlank와@Validated를 적용하면 컨트롤러 진입 전에 검증 가능합니다.catch (Exception e)로 모든 예외를 묶으면 원인 파악이 어려워집니다.IOException,JsonProcessingException, 서비스 예외 등을 구분해 로그와 사용자 메시지를 분리해 주세요.
🤖 Prompt for AI Agents
In src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java
around lines 59 to 66, add @NotBlank annotations to the petName and location
parameters to ensure they are not empty before entering the service logic, and
annotate the controller class or method with @Validated to enable validation.
Also, replace the generic catch (Exception e) block with multiple specific catch
blocks for IOException, JsonProcessingException, and service-specific exceptions
to separate logging and user messages for each error type, improving error
clarity and handling.
| 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<String, String> promptMapper = new ObjectMapper().readValue(jsonPrompt, new TypeReference<>() {}); | ||
| RecommendResponseDTO recommendation = recommendService.recommend(promptMapper); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
file.getBytes() 호출로 메모리 두 번 사용
이미지 파일이 큰 경우 getBytes() 로 전체 바이트 배열을 생성하면서, 동일 파일을 visionService.analyze(file, …) 에 다시 전달하여 이중 메모리 사용이 발생합니다.
-String interim = visionUseCase.interim(file.getBytes(), petName);
-String visionReport = visionService.analyze(file, petName);
+byte[] imageBytes = file.getBytes();
+String interim = visionUseCase.interim(imageBytes, petName);
+String visionReport = visionService.analyze(imageBytes, petName); // analyze 메서드를 byte[] 버전으로 오버로드하거나 기존 시그니처 수정 권장VisionServiceImpl 에 byte 배열 입력을 받는 오버로드를 추가하면 효율적입니다.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java
around lines 44 to 46, the code calls file.getBytes() to pass a byte array to
visionUseCase.interim, then passes the original file again to
visionService.analyze, causing duplicate memory usage for large files. To fix
this, add an overloaded method in VisionServiceImpl that accepts a byte array
input, then reuse the byte array from file.getBytes() for both calls to avoid
loading the file twice in memory.
📜 PR 내용 요약
⚒️ 작업 및 변경 내용(상세하게)
UnifiedFlowController의 메서드를 분할하였습니다.unifiedFlow.html의 JS 코드를 수정하였습니다.📚 기타 참고 사항