[LLM] 추천 결과 및 상세 페이지 추가#39
Conversation
… feat/regionSearch3
Feat/region search3
… feat/regionSearch3
Feat/region search3
… feat/regionSearch3
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary by CodeRabbit
Walkthrough추천 컨트롤러가 기존 REST API에서 HTML 뷰 렌더링을 지원하도록 변경되었으며, 추천 상세 페이지를 위한 새로운 GET 엔드포인트와 템플릿이 추가되었습니다. 추천 서비스와 재정렬 로직이 Document 기반으로 변경되고, 추천 결과 템플릿과 스타일이 확장되었습니다. 세션 데이터 초기화 로직도 일부 컨트롤러에 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant RecommendController
participant RecommendServiceImpl
participant GeminiRerankingService
participant ContentService
participant TourService
participant View
User->>RecommendController: POST /api/recommend (promptMap)
RecommendController->>RecommendServiceImpl: recommend(promptMap)
RecommendServiceImpl->>GeminiRerankingService: rerankGemini(userPrompt, List<Document>)
GeminiRerankingService-->>RecommendServiceImpl: GeminiRerankResponseDTO
RecommendServiceImpl->>ContentService: getContentById (for each ranked place)
ContentService-->>RecommendServiceImpl: Content details
RecommendServiceImpl-->>RecommendController: RecommendResponseDTO
RecommendController-->>User: JSON 응답
User->>RecommendController: GET /recommend/detail/{contentId}
RecommendController->>TourService: getTourDetail(contentId)
TourService-->>RecommendController: Detail data
RecommendController->>View: recommend_detail.html 렌더링
View-->>User: 상세 페이지 표시
Possibly related PRs
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. ✨ 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 (
|
There was a problem hiding this comment.
Actionable comments posted: 2
🔭 Outside diff range comments (3)
src/main/java/io/github/petty/llm/service/GeminiRerankingService.java (2)
44-91: 🛠️ Refactor suggestion프롬프트 개선사항이 우수합니다.
프롬프트의 다음 개선사항들이 매우 좋습니다:
- 추천 이유 길이를 100자로 증가
- 자연스러운 평문 요구
- 반려동물 조건 부합 필터링 강화
- 장소 타입별 필터링 추가
하지만 메타데이터 접근 시 안전성 개선이 필요합니다.
메타데이터 필드 접근 시 null 안전성을 개선해주세요:
- String contentId = (String) doc.getMetadata().get("contentId"); - String title = (String) doc.getMetadata().get("title"); - String addr = (String) doc.getMetadata().get("address"); + String contentId = (String) doc.getMetadata().getOrDefault("contentId", "Unknown"); + String title = (String) doc.getMetadata().getOrDefault("title", "제목 없음"); + String addr = (String) doc.getMetadata().getOrDefault("address", "주소 없음");
118-124:⚠️ Potential issue중복된 상태 코드 검사를 제거해주세요.
동일한 상태 코드 검사가 두 번 반복되고 있습니다. 중복 코드를 제거해야 합니다.
다음과 같이 중복 코드를 제거해주세요:
if (response.statusCode() != 200) { throw new RuntimeException("Gemini API 호출 실패: " + response.statusCode()); } - if (response.statusCode() != 200) { - throw new RuntimeException("Gemini API 호출 실패: " + response.statusCode()); - } - GeminiResponseDTO resp = objectMapper.readValue(response.body(), GeminiResponseDTO.class);src/main/java/io/github/petty/llm/service/RecommendServiceImpl.java (1)
70-74:⚠️ Potential issueNull 안전성 개선 필요
isDanger가 null일 경우NullPointerException이 발생할 수 있습니다.다음과 같이 null-safe 비교를 사용하세요:
-if (isDanger.equals("true")) { +if ("true".equals(isDanger)) { sb.append("맹견이에요\n"); } else { sb.append("소형견, 중형견이에요\n"); }
🧹 Nitpick comments (7)
src/main/java/io/github/petty/llm/controller/RecommendController.java (2)
22-26: 컨트롤러 역할 분리 고려동일한 컨트롤러에서 REST API와 HTML 뷰를 모두 처리하고 있습니다. 향후 유지보수를 위해 API 엔드포인트와 웹 페이지 컨트롤러를 분리하는 것을 고려해보세요.
38-51: 상세 페이지 엔드포인트 개선 제안에러 처리는 적절하나 다음 사항들을 고려해보세요:
contentId유효성 검증 추가 (예: 음수 값 체크)- 일반
Exception대신 구체적인 예외 처리 고려다음과 같이 개선할 수 있습니다:
public String getRecommendDetail(@PathVariable String contentId, Model model) { try { Long id = Long.parseLong(contentId); + if (id <= 0) { + model.addAttribute("error", "유효하지 않은 콘텐츠 ID입니다: " + contentId); + return "recommend_detail"; + } DetailCommonDto contentDetail = tourService.getContentDetailById(id); model.addAttribute("contentDetail", contentDetail); return "recommend_detail"; } catch (NumberFormatException e) { model.addAttribute("error", "잘못된 콘텐츠 ID입니다: " + contentId); return "recommend_detail"; - } catch (Exception e) { + } catch (IllegalArgumentException e) { + model.addAttribute("error", "콘텐츠를 찾을 수 없습니다: " + contentId); + return "recommend_detail"; + } catch (RuntimeException e) { model.addAttribute("error", "콘텐츠 정보를 불러오는데 실패했습니다: " + e.getMessage()); return "recommend_detail"; } }src/main/resources/templates/recommend_detail.html (1)
9-165: CSS를 외부 파일로 분리 권장템플릿 내 인라인 CSS가 너무 많습니다. 유지보수성을 위해 외부 CSS 파일로 분리하는 것을 고려해보세요.
/static/css/recommend_detail.css파일을 생성하고 다음과 같이 참조하세요:<th:block layout:fragment="css"> - <style> - /* 모든 CSS 내용 */ - </style> + <link rel="stylesheet" th:href="@{/css/recommend_detail.css}"> </th:block>src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java (2)
52-55: 중복된 세션 제거 로직POST 핸들러에서 세션을 다시 제거하는 것은 불필요해 보입니다. GET 요청에서 이미 제거했기 때문입니다.
POST 핸들러에서 중복 제거 로직을 삭제하거나 주석으로 이유를 명시하세요:
-// 세션 한 번 더 제거 -session.removeAttribute("recommendationResult"); -session.removeAttribute("visionReport"); -session.removeAttribute("lastAccessTime"); +// GET 요청에서 이미 세션을 정리했으므로 추가 제거 불필요
118-119: 주석 처리된 코드 정리 필요
is_danger파라미터가 주석 처리되어 있습니다- 결과 표시 후 세션 제거 로직이 주석 처리되어 있습니다
사용하지 않는 코드는 삭제하거나, 향후 계획이 있다면 TODO 주석을 추가하세요:
-// @RequestParam("is_danger") String isDanger, +// TODO: 맹견 여부 파라미터 추가 예정 +// @RequestParam("is_danger") String isDanger,Also applies to: 182-185
src/main/java/io/github/petty/llm/service/RecommendServiceImpl.java (2)
5-5: 사용하지 않는 import 제거
PointsInternalService가 사용되지 않고 있습니다.-import io.qdrant.client.grpc.PointsInternalService;
114-163: 추천 응답 생성 로직 확인중복 제거와 에러 처리가 적절히 구현되어 있습니다.
로그 레벨 개선을 고려해보세요:
-log.error("contentId {}에 대한 정보 조회 중 오류 발생: {}", contentId, e.getMessage()); +log.warn("contentId {}에 대한 정보 조회 실패, 건너뜁니다: {}", contentId, e.getMessage());
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/main/java/io/github/petty/llm/controller/RecommendController.java(2 hunks)src/main/java/io/github/petty/llm/dto/RecommendResponseDTO.java(2 hunks)src/main/java/io/github/petty/llm/service/GeminiRerankingService.java(5 hunks)src/main/java/io/github/petty/llm/service/RecommendServiceImpl.java(7 hunks)src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java(4 hunks)src/main/java/io/github/petty/tour/repository/PetTourInfoRepository.java(1 hunks)src/main/resources/static/css/result.css(1 hunks)src/main/resources/static/js/flow.js(1 hunks)src/main/resources/templates/recommend_detail.html(1 hunks)src/main/resources/templates/recommendation_result.html(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/io/github/petty/llm/controller/RecommendController.java (1)
src/main/java/io/github/petty/IndexController.java (1)
Controller(7-32)
🔇 Additional comments (12)
src/main/resources/static/js/flow.js (1)
141-141: 개행 추가 승인
파일 끝에 개행(newline)을 추가하여 POSIX 호환성을 확보했습니다.src/main/resources/static/css/result.css (1)
1-26: 잘 작성된 CSS 스타일입니다.추천 카드 레이아웃을 위한 CSS가 매우 잘 구현되었습니다:
- CSS Grid의
repeat(auto-fill, minmax(280px, 1fr))사용으로 반응형 디자인 구현- 적절한 패딩, 마진, 그림자 효과로 시각적 계층 구조 명확화
object-fit: cover를 통한 이미지 비율 유지- 일관된 간격 설정으로 깔끔한 UI 제공
src/main/java/io/github/petty/llm/dto/RecommendResponseDTO.java (1)
6-21: 코드 포맷팅 개선이 잘 되었습니다.일관된 코드 스타일을 위한 포맷팅 변경이 적절하게 적용되었습니다. 기능적 변경 없이 가독성만 향상되었습니다.
src/main/resources/templates/recommendation_result.html (3)
72-82: 카드 링크 스타일이 잘 구현되었습니다.전체 카드를 클릭 가능하게 만드는 CSS 스타일이 적절하게 구현되었습니다.
text-decoration: none과color: inherit를 통해 링크임을 숨기면서도 사용성을 향상시켰습니다.
102-105: Null 안전성이 잘 구현되었습니다.Elvis 연산자(
?:)를 사용하여 null 값에 대한 fallback 텍스트 "정보 없음"을 제공하는 것이 좋은 구현입니다. 사용자 경험을 향상시킵니다.
91-109:Details
❓ Verification inconclusive
데이터 바인딩 변경사항을 검증해주세요.
템플릿에서
${recommendationResponse}에서${recommendation}으로 데이터 바인딩이 변경되었고, 새로운 필드들(추천 이유, 가능 동물 등)이 추가되었습니다. 컨트롤러에서 올바른 모델 속성을 전달하는지 확인이 필요합니다.다음 스크립트로 컨트롤러의 모델 속성 설정을 확인해보겠습니다:
🏁 Script executed:
#!/bin/bash # RecommendController에서 모델 속성 설정 확인 ast-grep --pattern 'model.addAttribute("recommendation", $_)' # 또는 rg로 모델 속성 설정 확인 rg "addAttribute.*recommendation" -A 2 -B 2Length of output: 1578
🏁 Script executed:
#!/bin/bash # RecommendResponseDTO 정의 확인 rg "class RecommendResponseDTO" -A 50 -B 0 # 추천 리스트 아이템 DTO(Place) 정의 확인 rg "class .*Recommend.*DTO" -A 50 -B 0Length of output: 85
#!/bin/bash # RecommendService 클래스 및 recommend 메서드 시그니처 확인 rg "class .*RecommendService" -n src/main/java/io/github/petty/pipeline/service rg "recommend(" -n src/main/java/io/github/petty/pipeline/service # RecommendResponseDTO 또는 DTO 패키지 내 클래스 검색 rg "package .*dto" -n src/main/java/io/github/petty/pipeline rg "class .*ResponseDTO" -n src/main/java/io/github/petty/pipeline
#!/bin/bash # 프로젝트 내 Recommend 관련 Java 파일 목록 확인 find src/main/java -type f -name "*Recommend*.java" # RecommendResponse 또는 Recommendation DTO 클래스 정의 검색 rg "class .*RecommendResponse" -n src/main/java rg "class .*Recommendation" -n src/main/java
#!/bin/bash # 프로젝트의 pipeline 패키지 내 파일 구조 살펴보기 find src/main/java/io/github/petty/pipeline -maxdepth 4 -type f # DTO 또는 응답 모델 클래스 검색 rg "class .*(Response|Recommendation|Result).*" -n src/main/java/io/github/petty/pipeline # 서비스 클래스 및 recommend 메서드 확인 rg "class .*Service" -n src/main/java/io/github/petty/pipeline/service rg "recommend(" -n src/main/java/io/github/petty/pipeline/service
컨트롤러에서 전달되는
recommendation모델 속성 검증 필요템플릿에서
${recommendationResponse}→${recommendation}으로 바인딩이 변경되었고, 다음과 같은 새로운 필드를 사용하고 있습니다. 컨트롤러와 DTO(또는 응답 모델)에서 이들이 올바르게 설정되는지 확인해주세요.
- UnifiedFlowController.java (라인 178)
- model.addAttribute("recommendation", recommendation);
- PipelineController.java (라인 58)
- model.addAttribute("recommendation", prompt);
검증 포인트:
recommendation객체에
List<?> recommend필드가 존재하는지- 각 요소에
contentId,imageUrl,title,addr
recommendReason,acmpyPsblCpam,acmpyTypeCd,acmpyNeedMtr필드 및 getter가 정의되어 있는지- 서비스 로직에서 해당 필드들이 정상적으로 채워지는지
위 사항을 확인 후 템플릿 바인딩이 정상 동작하는지 검증 부탁드립니다.
src/main/java/io/github/petty/llm/service/GeminiRerankingService.java (2)
32-42: 메서드 시그니처 변경이 적절합니다.
List<RecommendResponseDTO.PlaceRecommend>에서List<Document>로 변경한 것은 재정렬 로직을 더 명확하게 분리하는 좋은 개선입니다. 관심사의 분리 원칙을 잘 적용했습니다.
72-76: 프롬프트 지시사항이 잘 개선되었습니다.특히 다음 개선사항들이 우수합니다:
- 추천 이유를 자연스러운 평문으로 요구
- 반려동물 동반 불가능한 장소 제외
- 사용자 지정 장소 타입별 필터링
이러한 개선으로 추천 품질이 크게 향상될 것으로 예상됩니다.
src/main/java/io/github/petty/llm/controller/RecommendController.java (1)
28-34: API 엔드포인트 변경 사항 확인됨기존 JSON 응답을 유지하면서
/api/recommend경로로 명시적으로 매핑한 것이 좋습니다.src/main/resources/templates/recommend_detail.html (1)
228-276: 반려동물 정보 섹션 구현 확인조건부 렌더링과 null 체크가 적절히 구현되어 있습니다.
src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java (1)
27-29:Details
❌ Incorrect review comment
의존성 주입 중복 확인 필요
VisionUseCase와VisionServiceImpl이 모두 주입되어 있습니다. 주석에서도 언급했듯이, 이는 중복일 가능성이 있습니다.다음 스크립트로 두 클래스의 관계를 확인해보세요:
🏁 Script executed:
#!/bin/bash # VisionServiceImpl이 VisionUseCase를 구현하는지 확인 ast-grep --pattern 'class VisionServiceImpl implements $$$VisionUseCase$$$' # 두 서비스의 사용처 확인 rg -A 3 "visionUseCase\." rg -A 3 "visionService\."Length of output: 1693
의존성 주입 구조 검토 완료
VisionUseCase(interim 생성)와VisionServiceImpl(analyze 실행)는 서로 다른 책임을 수행하므로 중복이 아닙니다.
- 현재 두 필드는 각기 다른 메서드(
interim,analyze)를 호출하기 위해 주입된 것이 맞습니다.- 다만, 구체 클래스에 직접 의존하지 않도록
VisionServiceImpl대신VisionService인터페이스를 주입하거나, 필드명을visionServiceImpl등으로 명확히 표기하는 것을 권장합니다.Likely an incorrect or invalid review comment.
src/main/java/io/github/petty/llm/service/RecommendServiceImpl.java (1)
42-46: 빈 검색 결과 처리 적절함검색 결과가 없을 때 빈 리스트를 반환하는 것이 사용자 경험 측면에서 좋습니다.
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| import java.util.List; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
import 사용 여부를 확인해주세요.
java.util.List import가 추가되었지만, 현재 인터페이스에서는 List 타입을 사용하는 메서드가 보이지 않습니다. 실제 사용처가 있는지 확인이 필요합니다.
다음 스크립트로 이 import의 실제 사용을 확인해보겠습니다:
🏁 Script executed:
#!/bin/bash
# PetTourInfoRepository에서 List 타입 사용을 확인
ast-grep --pattern 'interface PetTourInfoRepository {
$$$
List<$_> $_($$$);
$$$
}'
# 또는 rg로 List 사용을 확인
rg "List" src/main/java/io/github/petty/tour/repository/PetTourInfoRepository.java -A 3 -B 3Length of output: 333
java.util.List import 제거 요청
현재 PetTourInfoRepository.java에서 java.util.List가 실제로 사용되지 않고 있으므로 불필요한 import입니다. 아래와 같이 제거 부탁드립니다.
- 파일:
src/main/java/io/github/petty/tour/repository/PetTourInfoRepository.java - 라인: 8
-import java.util.List;📝 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.
| import java.util.List; |
🤖 Prompt for AI Agents
In src/main/java/io/github/petty/tour/repository/PetTourInfoRepository.java at
line 8, the import statement for java.util.List is not used anywhere in the
interface. Remove this unused import statement to clean up the code and avoid
unnecessary imports.
| <div th:if="${contentDetail.homepage}" class="detail-item"> | ||
| <strong>🌐 홈페이지:</strong> | ||
| <span> | ||
| <a th:href="${contentDetail.homepage}" target="_blank" rel="noopener">홈페이지 바로가기</a> | ||
| </span> | ||
| </div> |
There was a problem hiding this comment.
외부 링크 보안 개선 필요
target="_blank"를 사용하는 외부 링크에 보안 속성이 누락되었습니다.
이미 rel="noopener"가 있지만 noreferrer도 추가하는 것이 좋습니다:
-<a th:href="${contentDetail.homepage}" target="_blank" rel="noopener">홈페이지 바로가기</a>
+<a th:href="${contentDetail.homepage}" target="_blank" rel="noopener noreferrer">홈페이지 바로가기</a>🤖 Prompt for AI Agents
In src/main/resources/templates/recommend_detail.html around lines 214 to 219,
the external link uses target="_blank" with rel="noopener" but is missing
rel="noreferrer" for improved security. Update the anchor tag's rel attribute to
include both "noopener" and "noreferrer" to enhance protection against potential
security risks when opening new tabs.
|
PR 잘 검토했습니다. 사용자 경험 개선부터 추천 시스템의 핵심 로직 강화까지 매우 인상적인 업데이트입니다. 주요 변경 사항과 긍정적인 부분들을 아래와 같이 정리해 보았습니다:
이번 PR 작업하시면서 고민 많이 하신 게 느껴지네요. 덕분에 사용자 경험도 좋아지고 시스템도 한결 탄탄해진 것 같습니다. 수고 많으셨어요. |
📜 PR 내용 요약
⚒️ 작업 및 변경 내용(상세하게)
vision - report - recommend로 연결 과정을 통합하였습니다GeminiRerankingService- Gemini Rerank 서비스를 도입하여 추천의 정확도를 높였습니다contentId를 이용하여 각 카드 클릭 시 장소 상세보기 페이지로 이동하는 기능 추가UnifiedFlowController의 세션 제거 파트 리팩토링GET /analyze메서드 변경 참고📚 기타 참고 사항