From f7f1e08b49a575f64223dbb4c3307edb89f73fee Mon Sep 17 00:00:00 2001 From: yuhalog Date: Tue, 17 Jun 2025 11:20:35 +0900 Subject: [PATCH] =?UTF-8?q?add:=20actuator=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../external/PythonAiTipGenerator.java | 143 ------------------ .../src/main/resources/application.yml | 14 +- smarketing-java/build.gradle | 1 + .../src/main/resources/application.yml | 18 +++ .../member/src/main/resources/application.yml | 18 +++ .../store/src/main/resources/application.yml | 18 +++ 6 files changed, 67 insertions(+), 145 deletions(-) delete mode 100644 smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/PythonAiTipGenerator.java diff --git a/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/PythonAiTipGenerator.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/PythonAiTipGenerator.java deleted file mode 100644 index e091fc5..0000000 --- a/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/PythonAiTipGenerator.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.won.smarketing.recommend.infrastructure.external; - -import com.won.smarketing.recommend.domain.model.MenuData; -import com.won.smarketing.recommend.domain.model.StoreData; -import com.won.smarketing.recommend.domain.model.StoreWithMenuData; -import com.won.smarketing.recommend.domain.service.AiTipGenerator; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; // 이 어노테이션이 누락되어 있었음 -import org.springframework.web.reactive.function.client.WebClient; - -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * Python AI 팁 생성 구현체 (날씨 정보 제거) - */ -@Slf4j -@Service // 추가된 어노테이션 -@RequiredArgsConstructor -public class PythonAiTipGenerator implements AiTipGenerator { - - private final WebClient webClient; - - @Value("${external.python-ai-service.base-url}") - private String pythonAiServiceBaseUrl; - - @Value("${external.python-ai-service.api-key}") - private String pythonAiServiceApiKey; - - @Value("${external.python-ai-service.timeout}") - private int timeout; - - @Override - public String generateTip(StoreWithMenuData storeWithMenuData) { - try { - log.debug("Python AI 서비스 직접 호출: store={}", storeWithMenuData.getStoreData().getStoreName()); - return callPythonAiService(storeWithMenuData); - - } catch (Exception e) { - log.error("Python AI 서비스 호출 실패, Fallback 처리: {}", e.getMessage()); - return createFallbackTip(storeWithMenuData); - } - } - - private String callPythonAiService(StoreWithMenuData storeWithMenuData) { - - try { - - StoreData storeData = storeWithMenuData.getStoreData(); - List menuDataList = storeWithMenuData.getMenuDataList(); - - // 메뉴 데이터를 Map 형태로 변환 - List> menuList = menuDataList.stream() - .map(menu -> { - Map menuMap = new HashMap<>(); - menuMap.put("menu_id", menu.getMenuId()); - menuMap.put("menu_name", menu.getMenuName()); - menuMap.put("category", menu.getCategory()); - menuMap.put("price", menu.getPrice()); - menuMap.put("description", menu.getDescription()); - return menuMap; - }) - .collect(Collectors.toList()); - - // Python AI 서비스로 전송할 데이터 (매장 정보 + 메뉴 정보) - Map requestData = new HashMap<>(); - requestData.put("store_name", storeData.getStoreName()); - requestData.put("business_type", storeData.getBusinessType()); - requestData.put("location", storeData.getLocation()); - requestData.put("seat_count", storeData.getSeatCount()); - requestData.put("menu_list", menuList); - - log.debug("Python AI 서비스 요청 데이터: {}", requestData); - - PythonAiResponse response = webClient - .post() - .uri(pythonAiServiceBaseUrl + "/api/v1/generate-marketing-tip") - .header("Authorization", "Bearer " + pythonAiServiceApiKey) - .header("Content-Type", "application/json") - .bodyValue(requestData) - .retrieve() - .bodyToMono(PythonAiResponse.class) - .timeout(Duration.ofMillis(timeout)) - .block(); - - if (response != null && response.getTip() != null && !response.getTip().trim().isEmpty()) { - log.debug("Python AI 서비스 응답 성공: tip length={}", response.getTip().length()); - return response.getTip(); - } - } catch (Exception e) { - log.error("Python AI 서비스 실제 호출 실패: {}", e.getMessage()); - } - - return createFallbackTip(storeWithMenuData); - } - - /** - * 규칙 기반 Fallback 팁 생성 (날씨 정보 없이 매장 정보만 활용) - */ - private String createFallbackTip(StoreWithMenuData storeWithMenuData) { - String businessType = storeWithMenuData.getStoreData().getBusinessType(); - String storeName = storeWithMenuData.getStoreData().getStoreName(); - String location = storeWithMenuData.getStoreData().getLocation(); - - // 업종별 기본 팁 생성 - if (businessType.contains("카페")) { - return String.format("%s만의 시그니처 음료와 디저트로 고객들에게 특별한 경험을 선사해보세요!", storeName); - } else if (businessType.contains("음식점") || businessType.contains("식당")) { - return String.format("%s의 대표 메뉴를 활용한 특별한 이벤트로 고객들의 관심을 끌어보세요!", storeName); - } else if (businessType.contains("베이커리") || businessType.contains("빵집")) { - return String.format("%s의 갓 구운 빵과 함께하는 따뜻한 서비스로 고객들의 마음을 사로잡아보세요!", storeName); - } else if (businessType.contains("치킨") || businessType.contains("튀김")) { - return String.format("%s의 바삭하고 맛있는 메뉴로 고객들에게 만족스러운 식사를 제공해보세요!", storeName); - } - - // 지역별 팁 - if (location.contains("강남") || location.contains("서초")) { - return String.format("%s에서 트렌디하고 세련된 서비스로 젊은 고객층을 공략해보세요!", storeName); - } else if (location.contains("홍대") || location.contains("신촌")) { - return String.format("%s에서 활기차고 개성 있는 이벤트로 대학생들의 관심을 끌어보세요!", storeName); - } - - // 기본 팁 - return String.format("%s만의 특별함을 살린 고객 맞춤 서비스로 단골 고객을 늘려보세요!", storeName); - } - - @Getter - private static class PythonAiResponse { - private String tip; - private String status; - private String message; - private LocalDateTime generatedTip; - private String businessType; - private String aiModel; - } -} \ No newline at end of file diff --git a/smarketing-java/ai-recommend/src/main/resources/application.yml b/smarketing-java/ai-recommend/src/main/resources/application.yml index ee94915..72aa217 100644 --- a/smarketing-java/ai-recommend/src/main/resources/application.yml +++ b/smarketing-java/ai-recommend/src/main/resources/application.yml @@ -43,10 +43,13 @@ management: endpoints: web: exposure: - include: health,info,metrics + include: health,info + base-path: /actuator endpoint: health: show-details: always + info: + enabled: true logging: level: @@ -55,4 +58,11 @@ logging: jwt: secret: ${JWT_SECRET:mySecretKeyForJWTTokenGenerationAndValidation123456789} access-token-validity: ${JWT_ACCESS_VALIDITY:3600000} - refresh-token-validity: ${JWT_REFRESH_VALIDITY:604800000} \ No newline at end of file + refresh-token-validity: ${JWT_REFRESH_VALIDITY:604800000} + + +info: + app: + name: ${APP_NAME:smarketing-recommend} + version: "1.0.0-MVP" + description: "AI 마케팅 서비스 MVP - recommend" \ No newline at end of file diff --git a/smarketing-java/build.gradle b/smarketing-java/build.gradle index d0a82d4..e917ca4 100644 --- a/smarketing-java/build.gradle +++ b/smarketing-java/build.gradle @@ -35,6 +35,7 @@ subprojects { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' implementation 'io.jsonwebtoken:jjwt-api:0.12.3' implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' diff --git a/smarketing-java/marketing-content/src/main/resources/application.yml b/smarketing-java/marketing-content/src/main/resources/application.yml index 59b0b54..aefce5c 100644 --- a/smarketing-java/marketing-content/src/main/resources/application.yml +++ b/smarketing-java/marketing-content/src/main/resources/application.yml @@ -37,3 +37,21 @@ logging: external: ai-service: base-url: ${AI_SERVICE_BASE_URL:http://20.249.139.88:5001} + +management: + endpoints: + web: + exposure: + include: health,info + base-path: /actuator + endpoint: + health: + show-details: always + info: + enabled: true + +info: + app: + name: ${APP_NAME:smarketing-content} + version: "1.0.0-MVP" + description: "AI 마케팅 서비스 MVP - content" \ No newline at end of file diff --git a/smarketing-java/member/src/main/resources/application.yml b/smarketing-java/member/src/main/resources/application.yml index 6f1de12..80c2281 100644 --- a/smarketing-java/member/src/main/resources/application.yml +++ b/smarketing-java/member/src/main/resources/application.yml @@ -31,3 +31,21 @@ jwt: logging: level: com.won.smarketing: ${LOG_LEVEL:DEBUG} + +management: + endpoints: + web: + exposure: + include: health,info + base-path: /actuator + endpoint: + health: + show-details: always + info: + enabled: true + +info: + app: + name: ${APP_NAME:smarketing-member} + version: "1.0.0-MVP" + description: "AI 마케팅 서비스 MVP - member" \ No newline at end of file diff --git a/smarketing-java/store/src/main/resources/application.yml b/smarketing-java/store/src/main/resources/application.yml index 5a50cbc..bd9d023 100644 --- a/smarketing-java/store/src/main/resources/application.yml +++ b/smarketing-java/store/src/main/resources/application.yml @@ -46,3 +46,21 @@ azure: menu-images: ${AZURE_STORAGE_MENU_CONTAINER:smarketing-menu-images} store-images: ${AZURE_STORAGE_STORE_CONTAINER:smarketing-store-images} max-file-size: ${AZURE_STORAGE_MAX_FILE_SIZE:10485760} # 10MB + +management: + endpoints: + web: + exposure: + include: health,info + base-path: /actuator + endpoint: + health: + show-details: always + info: + enabled: true + +info: + app: + name: ${APP_NAME:smarketing-content} + version: "1.0.0-MVP" + description: "AI 마케팅 서비스 MVP - content" \ No newline at end of file