-
Notifications
You must be signed in to change notification settings - Fork 0
AI서버 장소추출 구현완료에 따른 콜백 api 개발 필요 #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "20260127_16_AI\uC11C\uBC84_\uC7A5\uC18C\uCD94\uCD9C_\uAD6C\uD604\uC644\uB8CC\uC5D0_\uB530\uB978_\uCF5C\uBC31_api_\uAC1C\uBC1C_\uD544\uC694"
Changes from 3 commits
ed8142a
0803695
ea42dd2
e00478c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ | |
|
|
||
| /** | ||
| * AI 서버로부터 Webhook Callback으로 받는 분석 결과 DTO | ||
| * | ||
| * @see <a href="https://github.com/MapSee-Lab/MapSy-BE/issues/16">GitHub Issue #16</a> | ||
| */ | ||
| @Getter | ||
| @Setter | ||
|
|
@@ -22,105 +24,200 @@ | |
| @AllArgsConstructor | ||
| public class AiCallbackRequest { | ||
|
|
||
| @Schema(description = "Content UUID", example = "550e8400-e29b-41d4-a716-446655440000") | ||
| @NotNull(message = "contentId는 필수입니다.") | ||
| private UUID contentId; | ||
|
|
||
| @Schema(description = "처리 결과 상태", example = "SUCCESS", allowableValues = {"SUCCESS", "FAILED"}) | ||
| @NotNull(message = "resultStatus는 필수입니다.") | ||
| private String resultStatus; | ||
|
|
||
| @Schema(description = "Content UUID (FAILED 상태일 때 필수, SUCCESS일 때는 contentInfo.contentId 사용 가능)") | ||
| private UUID contentId; | ||
| @Schema(description = "SNS 콘텐츠 정보 (SUCCESS 시 필수)") | ||
| @Valid | ||
| private SnsInfoCallback snsInfo; | ||
|
Comment on lines
+35
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: rg -n "snsInfo" --type=java -A 3 -B 1 MS-AI/src/main/javaRepository: MapSee-Lab/MapSy-BE Length of output: 521 🏁 Script executed: # Look specifically for AiCallbackService to see how it validates snsInfo
fd "AiCallbackService" --type f -e javaRepository: MapSee-Lab/MapSy-BE Length of output: 138 🏁 Script executed: # Also search for validation logic related to SUCCESS status
rg -n "SUCCESS|resultStatus" --type=java -A 2 -B 2 MS-AI/src/main/javaRepository: MapSee-Lab/MapSy-BE Length of output: 1018 🏁 Script executed: cat -n MS-SNS/src/main/java/kr/suhsaechan/mapsy/sns/service/AiCallbackService.javaRepository: MapSee-Lab/MapSy-BE Length of output: 26976 🏁 Script executed: # Also check if there are any validation exception classes or error handlers
rg -n "snsInfo.*null|SnsInfoCallback|AiCallback" --type=java MS-SNS/src/main/java -A 2 -B 1Repository: MapSee-Lab/MapSy-BE Length of output: 9671 SUCCESS 상태일 때
다음 중 하나를 권장합니다:
🤖 Prompt for AI Agents |
||
|
|
||
| @Schema(description = "콘텐츠 정보") | ||
| @Schema(description = "추출된 장소 상세 목록") | ||
| @Valid | ||
| private ContentInfo contentInfo; | ||
| private List<PlaceDetailCallback> placeDetails; | ||
|
|
||
| @Schema(description = "추출된 장소 목록") | ||
| @Schema(description = "추출 처리 통계") | ||
| @Valid | ||
| private List<PlaceInfo> places; | ||
| private ExtractionStatistics statistics; | ||
|
|
||
| @Schema(description = "실패 사유 (FAILED 시)") | ||
| private String errorMessage; | ||
|
|
||
| /** | ||
| * 콘텐츠 정보 | ||
| * SNS 콘텐츠 정보 | ||
| */ | ||
| @Getter | ||
| @Setter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| public static class ContentInfo { | ||
|
|
||
| @Schema(description = "Content UUID (백엔드에서 전송받은 UUID)", example = "123e4567-e89b-12d3-a456-426614174000") | ||
| @NotNull(message = "contentId는 필수입니다.") | ||
| private UUID contentId; | ||
| public static class SnsInfoCallback { | ||
|
|
||
| @Schema(description = "썸네일 URL", example = "https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg") | ||
| @NotNull(message = "thumbnailUrl은 필수입니다.") | ||
| private String thumbnailUrl; | ||
|
|
||
| @Schema(description = "SNS 플랫폼", example = "YOUTUBE", allowableValues = {"INSTAGRAM", "YOUTUBE", "YOUTUBE_SHORTS"}) | ||
| @Schema(description = "SNS 플랫폼", example = "INSTAGRAM", | ||
| allowableValues = {"INSTAGRAM", "YOUTUBE", "YOUTUBE_SHORTS", "TIKTOK", "FACEBOOK", "TWITTER"}) | ||
| @NotNull(message = "platform은 필수입니다.") | ||
| private String platform; | ||
|
|
||
| @Schema(description = "콘텐츠 제목", example = "일본 전국 라멘 투어 - 개당 1200원의 가성비 초밥") | ||
| // 필수 아님 | ||
| private String title; | ||
| @Schema(description = "콘텐츠 타입", example = "reel") | ||
| @NotNull(message = "contentType은 필수입니다.") | ||
| private String contentType; | ||
|
|
||
| @Schema(description = "원본 SNS URL", example = "https://www.instagram.com/reel/ABC123/") | ||
| @NotNull(message = "url은 필수입니다.") | ||
| private String url; | ||
|
|
||
| @Schema(description = "작성자 ID", example = "username") | ||
| private String author; | ||
|
|
||
| @Schema(description = "게시물 본문", example = "여기 정말 맛있어! #맛집 #서울") | ||
| private String caption; | ||
|
|
||
| @Schema(description = "좋아요 수", example = "1234") | ||
| private Integer likesCount; | ||
|
|
||
| @Schema(description = "댓글 수", example = "56") | ||
| private Integer commentsCount; | ||
|
|
||
| @Schema(description = "콘텐츠 URL", example = "https://www.youtube.com/watch?v=VIDEO_ID") | ||
| private String contentUrl; | ||
| @Schema(description = "게시 날짜 (ISO 8601)", example = "2024-01-15T10:30:00Z") | ||
| private String postedAt; | ||
|
|
||
| @Schema(description = "업로더 아이디", example = "travel_lover_123") | ||
| private String platformUploader; | ||
| @Schema(description = "해시태그 리스트", example = "[\"맛집\", \"서울\"]") | ||
| private List<String> hashtags; | ||
|
|
||
| @Schema(description = "AI 콘텐츠 요약", example = "샷포로 3대 스시 맛집 '토리톤' 방문...") | ||
| private String summary; | ||
| @Schema(description = "대표 이미지/썸네일 URL", example = "https://...") | ||
| private String thumbnailUrl; | ||
|
|
||
| @Schema(description = "이미지 URL 리스트", example = "[\"https://...\"]") | ||
| private List<String> imageUrls; | ||
|
|
||
| @Schema(description = "작성자 프로필 이미지 URL", example = "https://...") | ||
| private String authorProfileImageUrl; | ||
| } | ||
|
|
||
| /** | ||
| * 장소 정보 | ||
| * 장소 상세 정보 | ||
| */ | ||
| @Getter | ||
| @Setter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| public static class PlaceInfo { | ||
| public static class PlaceDetailCallback { | ||
|
|
||
| @Schema(description = "장소명", example = "명동 교자") | ||
| // 기본 정보 | ||
| @Schema(description = "네이버 Place ID", example = "11679241") | ||
| @NotNull(message = "placeId는 필수입니다.") | ||
| private String placeId; | ||
|
|
||
| @Schema(description = "장소명", example = "늘푸른목장 잠실본점") | ||
| @NotNull(message = "name은 필수입니다.") | ||
| private String name; | ||
|
|
||
| @Schema(description = "주소", example = "서울특별시 중구 명동길 29") | ||
| @NotNull(message = "address는 필수입니다.") | ||
| private String address; | ||
| @Schema(description = "카테고리", example = "소고기구이") | ||
| private String category; | ||
|
|
||
| @Schema(description = "위도", example = "37.563476", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| @NotNull(message = "latitude는 필수입니다.") | ||
| @Schema(description = "한줄 설명", example = "된장찌개와 냉면으로 완성하는 한상차림") | ||
| private String description; | ||
|
|
||
| // 위치 정보 | ||
| @Schema(description = "위도", example = "37.5112") | ||
| private Double latitude; | ||
|
|
||
| @Schema(description = "경도", example = "126.983920", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| @NotNull(message = "longitude는 필수입니다.") | ||
| @Schema(description = "경도", example = "127.0867") | ||
| private Double longitude; | ||
|
|
||
| @Schema(description = "국가 코드 (ISO 3166-1 alpha-2)", example = "KR") | ||
| private String country; | ||
| @Schema(description = "지번 주소", example = "서울 송파구 백제고분로9길 34 1F") | ||
| private String address; | ||
|
|
||
| @Schema(description = "도로명 주소", example = "서울 송파구 백제고분로9길 34 1F") | ||
| private String roadAddress; | ||
|
|
||
| @Schema(description = "카테고리", example = "한식 음식점") | ||
| private String category; | ||
| @Schema(description = "지하철 정보", example = "잠실새내역 4번 출구에서 412m") | ||
| private String subwayInfo; | ||
|
|
||
| @Schema(description = "전화번호", example = "02-776-5348") | ||
| private String phone; | ||
| @Schema(description = "찾아가는 길", example = "잠실새내역 4번 출구에서 맥도널드 골목 끼고...") | ||
| private String directionsText; | ||
|
|
||
| @Schema(description = "영업시간", example = "매일 10:30 - 21:30") | ||
| private String openingHours; | ||
| // 평점/리뷰 | ||
| @Schema(description = "별점 (0.0~5.0)", example = "4.42") | ||
| private Double rating; | ||
|
|
||
| @Schema(description = "장소 설명", example = "칼국수와 만두로 유명한 맛집") | ||
| private String description; | ||
| @Schema(description = "방문자 리뷰 수", example = "1510") | ||
| private Integer visitorReviewCount; | ||
|
|
||
| @Schema(description = "AI 추출 원본 데이터", example = "명동 교자에서 칼국수 먹었어요 (caption, confidence: 0.95)") | ||
| private String rawData; | ||
| @Schema(description = "블로그 리뷰 수", example = "1173") | ||
| private Integer blogReviewCount; | ||
|
|
||
| @Schema(description = "언어 코드 (ISO 639-1)", example = "ko", allowableValues = {"ko", "en", "ja", "zh"}) | ||
| private String language = "ko"; | ||
| // 영업 정보 | ||
| @Schema(description = "영업 상태", example = "영업 중") | ||
| private String businessStatus; | ||
|
|
||
| @Schema(description = "키워드 목록", example = "[\"#명동맛집\", \"#칼국수\", \"#만두\"]") | ||
| @Schema(description = "영업 시간 요약", example = "24:00에 영업 종료") | ||
| private String businessHours; | ||
|
|
||
| @Schema(description = "요일별 상세 영업시간", example = "[\"월 11:30 - 24:00\", \"화 11:30 - 24:00\"]") | ||
| private List<String> openHoursDetail; | ||
|
|
||
| @Schema(description = "휴무일 정보", example = "연중무휴") | ||
| private String holidayInfo; | ||
|
|
||
| // 연락처/링크 | ||
| @Schema(description = "전화번호", example = "02-3431-4520") | ||
| private String phoneNumber; | ||
|
|
||
| @Schema(description = "홈페이지 URL", example = "http://example.com") | ||
| private String homepageUrl; | ||
|
|
||
| @Schema(description = "네이버 지도 URL", example = "https://map.naver.com/p/search/늘푸른목장/place/11679241") | ||
| private String naverMapUrl; | ||
|
|
||
| @Schema(description = "예약 가능 여부", example = "true") | ||
| private Boolean reservationAvailable; | ||
|
|
||
| // 부가 정보 | ||
| @Schema(description = "편의시설 목록", example = "[\"단체 이용 가능\", \"주차\", \"발렛파킹\"]") | ||
| private List<String> amenities; | ||
|
|
||
| @Schema(description = "키워드/태그", example = "[\"소고기\", \"한우\", \"회식\"]") | ||
| private List<String> keywords; | ||
|
|
||
| @Schema(description = "TV 방송 출연 정보", example = "[\"줄서는식당 14회 (24.05.13)\"]") | ||
| private List<String> tvAppearances; | ||
|
|
||
| @Schema(description = "대표 메뉴", example = "[\"경주갈비살\", \"한우된장밥\"]") | ||
| private List<String> menuInfo; | ||
|
|
||
| @Schema(description = "대표 이미지 URL", example = "https://...") | ||
| private String imageUrl; | ||
|
|
||
| @Schema(description = "이미지 URL 목록", example = "[\"https://...\"]") | ||
| private List<String> imageUrls; | ||
| } | ||
|
|
||
| /** | ||
| * 추출 처리 통계 | ||
| */ | ||
| @Getter | ||
| @Setter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| public static class ExtractionStatistics { | ||
|
|
||
| @Schema(description = "LLM이 추출한 장소명 리스트", example = "[\"늘푸른목장\", \"강남역\"]") | ||
| private List<String> extractedPlaceNames; | ||
|
|
||
| @Schema(description = "LLM이 추출한 장소 수", example = "2") | ||
| private Integer totalExtracted; | ||
|
|
||
| @Schema(description = "네이버 지도에서 찾은 장소 수", example = "1") | ||
| private Integer totalFound; | ||
|
|
||
| @Schema(description = "검색 실패한 장소명", example = "[\"강남역\"]") | ||
| private List<String> failedSearches; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swagger 엔드포인트를 Health Check 경로로 사용 시 신뢰성 저하 가능성
/actuator/health는 Spring Boot의 전용 헬스체크 엔드포인트로, 애플리케이션 상태(DB 연결, 외부 서비스 등)를 확인하여{"status":"UP"}형태의 JSON을 반환합니다. 반면/docs/swagger는 Swagger UI HTML 페이지로:API_DOCS_PATH는 이미 배포 완료 코멘트에 표시 용도로 사용되고 있으므로,HEALTH_CHECK_PATH는 기존/actuator/health로 유지하는 것이 더 신뢰성 있는 헬스체크가 됩니다.🔧 제안: 기존 health endpoint 유지
📝 Committable suggestion
🤖 Prompt for AI Agents