mirror of
https://github.com/won-ktds/smarketing-backend.git
synced 2026-01-21 11:06:23 +00:00
refactor: actuator health
This commit is contained in:
parent
14c5164c41
commit
70ea983da4
@ -50,6 +50,11 @@ management:
|
||||
show-details: always
|
||||
info:
|
||||
enabled: true
|
||||
health:
|
||||
livenessState:
|
||||
enabled: true
|
||||
readinessState:
|
||||
enabled: true
|
||||
|
||||
logging:
|
||||
level:
|
||||
|
||||
@ -16,6 +16,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -32,25 +33,20 @@ public class PosterContentService implements PosterContentUseCase {
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 생성
|
||||
*
|
||||
*
|
||||
* @param request 포스터 콘텐츠 생성 요청
|
||||
* @return 생성된 포스터 콘텐츠 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public PosterContentCreateResponse generatePosterContent(PosterContentCreateRequest request) {
|
||||
// AI를 사용하여 포스터 생성
|
||||
|
||||
String generatedPoster = aiPosterGenerator.generatePoster(request);
|
||||
|
||||
// 다양한 사이즈의 포스터 생성
|
||||
Map<String, String> posterSizes = aiPosterGenerator.generatePosterSizes(generatedPoster);
|
||||
|
||||
// 생성 조건 정보 구성
|
||||
CreationConditions conditions = CreationConditions.builder()
|
||||
.category(request.getCategory())
|
||||
.requirement(request.getRequirement())
|
||||
// .toneAndManner(request.getToneAndManner())
|
||||
// .emotionIntensity(request.getEmotionIntensity())
|
||||
.eventName(request.getEventName())
|
||||
.startDate(request.getStartDate())
|
||||
.endDate(request.getEndDate())
|
||||
@ -62,47 +58,41 @@ public class PosterContentService implements PosterContentUseCase {
|
||||
.contentType(ContentType.POSTER.name())
|
||||
.title(request.getTitle())
|
||||
.posterImage(generatedPoster)
|
||||
.posterSizes(posterSizes)
|
||||
.posterSizes(new HashMap<>()) // 빈 맵 반환 (사이즈 변환 안함)
|
||||
.status(ContentStatus.DRAFT.name())
|
||||
//.createdAt(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 저장
|
||||
*
|
||||
*
|
||||
* @param request 포스터 콘텐츠 저장 요청
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void savePosterContent(PosterContentSaveRequest request) {
|
||||
// 생성 조건 정보 구성
|
||||
// 생성 조건 구성
|
||||
CreationConditions conditions = CreationConditions.builder()
|
||||
.category(request.getCategory())
|
||||
.requirement(request.getRequirement())
|
||||
// .toneAndManner(request.getToneAndManner())
|
||||
// .emotionIntensity(request.getEmotionIntensity())
|
||||
.eventName(request.getEventName())
|
||||
.startDate(request.getStartDate())
|
||||
.endDate(request.getEndDate())
|
||||
.photoStyle(request.getPhotoStyle())
|
||||
.build();
|
||||
|
||||
// 콘텐츠 엔티티 생성 및 저장
|
||||
// 콘텐츠 엔티티 생성
|
||||
Content content = Content.builder()
|
||||
.contentType(ContentType.POSTER)
|
||||
.platform(Platform.GENERAL) // 포스터는 범용
|
||||
.title(request.getTitle())
|
||||
.content(null) // 포스터는 이미지가 주 콘텐츠
|
||||
.hashtags(null)
|
||||
.content(request.getContent())
|
||||
.images(request.getImages())
|
||||
.status(ContentStatus.PUBLISHED)
|
||||
.creationConditions(conditions)
|
||||
.storeId(request.getStoreId())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.updatedAt(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
// 저장
|
||||
contentRepository.save(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
// marketing-content/src/main/java/com/won/smarketing/content/infrastructure/external/ClaudeAiPosterGenerator.java
|
||||
package com.won.smarketing.content.infrastructure.external;
|
||||
|
||||
import com.won.smarketing.content.domain.service.AiPosterGenerator; // 도메인 인터페이스 import
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Claude AI를 활용한 포스터 생성 구현체
|
||||
* Clean Architecture의 Infrastructure Layer에 위치
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ClaudeAiPosterGenerator implements AiPosterGenerator {
|
||||
|
||||
/**
|
||||
* 포스터 생성
|
||||
*
|
||||
* @param request 포스터 생성 요청
|
||||
* @return 생성된 포스터 이미지 URL
|
||||
*/
|
||||
@Override
|
||||
public String generatePoster(PosterContentCreateRequest request) {
|
||||
try {
|
||||
// Claude AI API 호출 로직
|
||||
String prompt = buildPosterPrompt(request);
|
||||
|
||||
// TODO: 실제 Claude AI API 호출
|
||||
// 현재는 더미 데이터 반환
|
||||
return generateDummyPosterUrl(request.getTitle());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("AI 포스터 생성 실패: {}", e.getMessage(), e);
|
||||
return generateFallbackPosterUrl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다양한 사이즈의 포스터 생성
|
||||
*
|
||||
* @param baseImage 기본 이미지
|
||||
* @return 사이즈별 포스터 URL 맵
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> generatePosterSizes(String baseImage) {
|
||||
Map<String, String> sizes = new HashMap<>();
|
||||
|
||||
// 다양한 사이즈 생성 (더미 구현)
|
||||
sizes.put("instagram_square", baseImage + "_1080x1080.jpg");
|
||||
sizes.put("instagram_story", baseImage + "_1080x1920.jpg");
|
||||
sizes.put("facebook_post", baseImage + "_1200x630.jpg");
|
||||
sizes.put("a4_poster", baseImage + "_2480x3508.jpg");
|
||||
|
||||
return sizes;
|
||||
}
|
||||
|
||||
private String buildPosterPrompt(PosterContentCreateRequest request) {
|
||||
StringBuilder prompt = new StringBuilder();
|
||||
prompt.append("포스터 제목: ").append(request.getTitle()).append("\n");
|
||||
prompt.append("카테고리: ").append(request.getCategory()).append("\n");
|
||||
|
||||
if (request.getRequirement() != null) {
|
||||
prompt.append("요구사항: ").append(request.getRequirement()).append("\n");
|
||||
}
|
||||
|
||||
if (request.getToneAndManner() != null) {
|
||||
prompt.append("톤앤매너: ").append(request.getToneAndManner()).append("\n");
|
||||
}
|
||||
|
||||
return prompt.toString();
|
||||
}
|
||||
|
||||
private String generateDummyPosterUrl(String title) {
|
||||
return "https://dummy-ai-service.com/posters/" + title.hashCode() + ".jpg";
|
||||
}
|
||||
|
||||
private String generateFallbackPosterUrl() {
|
||||
return "https://dummy-ai-service.com/posters/fallback.jpg";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
package com.won.smarketing.content.infrastructure.external;
|
||||
|
||||
import com.won.smarketing.content.domain.service.AiPosterGenerator; // 도메인 인터페이스 import
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Claude AI를 활용한 포스터 생성 구현체
|
||||
* Clean Architecture의 Infrastructure Layer에 위치
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PythonAiPosterGenerator implements AiPosterGenerator {
|
||||
|
||||
private final WebClient webClient;
|
||||
|
||||
@Value("${external.ai-service.base-url:http://20.249.139.88:5001}")
|
||||
private String aiServiceBaseUrl;
|
||||
|
||||
/**
|
||||
* 포스터 생성 - Python AI 서비스 호출
|
||||
*
|
||||
* @param request 포스터 생성 요청
|
||||
* @return 생성된 포스터 이미지 URL
|
||||
*/
|
||||
@Override
|
||||
public String generatePoster(PosterContentCreateRequest request) {
|
||||
try {
|
||||
log.info("Python AI 포스터 서비스 호출: {}/api/ai/poster", aiServiceBaseUrl);
|
||||
|
||||
// 요청 데이터 구성
|
||||
Map<String, Object> requestBody = buildRequestBody(request);
|
||||
|
||||
log.debug("포스터 생성 요청 데이터: {}", requestBody);
|
||||
|
||||
// Python AI 서비스 호출
|
||||
Map<String, Object> response = webClient
|
||||
.post()
|
||||
.uri(aiServiceBaseUrl + "/api/ai/poster")
|
||||
.header("Content-Type", "application/json")
|
||||
.bodyValue(requestBody)
|
||||
.retrieve()
|
||||
.bodyToMono(Map.class)
|
||||
.timeout(Duration.ofSeconds(60)) // 포스터 생성은 시간이 오래 걸릴 수 있음
|
||||
.block();
|
||||
|
||||
// 응답에서 content(이미지 URL) 추출
|
||||
if (response != null && response.containsKey("content")) {
|
||||
String imageUrl = (String) response.get("content");
|
||||
log.info("AI 포스터 생성 성공: imageUrl={}", imageUrl);
|
||||
return imageUrl;
|
||||
} else {
|
||||
log.warn("AI 포스터 생성 응답에 content가 없음: {}", response);
|
||||
return generateFallbackPosterUrl(request.getTitle());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("AI 포스터 생성 실패: {}", e.getMessage(), e);
|
||||
return generateFallbackPosterUrl(request.getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다양한 사이즈의 포스터 생성 (사용하지 않음)
|
||||
* 1개의 이미지만 생성하므로 빈 맵 반환
|
||||
*
|
||||
* @param baseImage 기본 이미지 URL
|
||||
* @return 빈 맵
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> generatePosterSizes(String baseImage) {
|
||||
log.info("포스터 사이즈 변환 기능은 사용하지 않음: baseImage={}", baseImage);
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Python AI 서비스 요청 데이터 구성
|
||||
* Python 서비스의 PosterContentGetRequest 모델에 맞춤
|
||||
*/
|
||||
private Map<String, Object> buildRequestBody(PosterContentCreateRequest request) {
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
|
||||
// 기본 정보
|
||||
requestBody.put("title", request.getTitle());
|
||||
requestBody.put("category", request.getCategory());
|
||||
requestBody.put("contentType", request.getContentType());
|
||||
|
||||
// 이미지 정보
|
||||
if (request.getImages() != null && !request.getImages().isEmpty()) {
|
||||
requestBody.put("images", request.getImages());
|
||||
}
|
||||
|
||||
// 스타일 정보
|
||||
if (request.getPhotoStyle() != null) {
|
||||
requestBody.put("photoStyle", request.getPhotoStyle());
|
||||
}
|
||||
|
||||
// 요구사항
|
||||
if (request.getRequirement() != null) {
|
||||
requestBody.put("requirement", request.getRequirement());
|
||||
}
|
||||
|
||||
// 톤앤매너
|
||||
if (request.getToneAndManner() != null) {
|
||||
requestBody.put("toneAndManner", request.getToneAndManner());
|
||||
}
|
||||
|
||||
// 감정 강도
|
||||
if (request.getEmotionIntensity() != null) {
|
||||
requestBody.put("emotionIntensity", request.getEmotionIntensity());
|
||||
}
|
||||
|
||||
// 메뉴명
|
||||
if (request.getMenuName() != null) {
|
||||
requestBody.put("menuName", request.getMenuName());
|
||||
}
|
||||
|
||||
// 이벤트 정보
|
||||
if (request.getEventName() != null) {
|
||||
requestBody.put("eventName", request.getEventName());
|
||||
}
|
||||
|
||||
// 날짜 정보 (LocalDate를 String으로 변환)
|
||||
if (request.getStartDate() != null) {
|
||||
requestBody.put("startDate", request.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
|
||||
}
|
||||
|
||||
if (request.getEndDate() != null) {
|
||||
requestBody.put("endDate", request.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
|
||||
}
|
||||
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* 폴백 포스터 URL 생성
|
||||
*/
|
||||
private String generateFallbackPosterUrl(String title) {
|
||||
// 기본 포스터 템플릿 URL 반환
|
||||
return "https://stdigitalgarage02.blob.core.windows.net/ai-content/fallback-poster.jpg";
|
||||
}
|
||||
}
|
||||
@ -49,6 +49,11 @@ management:
|
||||
show-details: always
|
||||
info:
|
||||
enabled: true
|
||||
health:
|
||||
livenessState:
|
||||
enabled: true
|
||||
readinessState:
|
||||
enabled: true
|
||||
|
||||
info:
|
||||
app:
|
||||
|
||||
@ -43,6 +43,11 @@ management:
|
||||
show-details: always
|
||||
info:
|
||||
enabled: true
|
||||
health:
|
||||
livenessState:
|
||||
enabled: true
|
||||
readinessState:
|
||||
enabled: true
|
||||
|
||||
info:
|
||||
app:
|
||||
|
||||
@ -58,6 +58,11 @@ management:
|
||||
show-details: always
|
||||
info:
|
||||
enabled: true
|
||||
health:
|
||||
livenessState:
|
||||
enabled: true
|
||||
readinessState:
|
||||
enabled: true
|
||||
|
||||
info:
|
||||
app:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user