mirror of
https://github.com/won-ktds/smarketing-backend.git
synced 2026-01-22 11:36:24 +00:00
feat: generate poster
This commit is contained in:
parent
4b7f6c11e6
commit
ffa4a7f0a9
@ -13,6 +13,8 @@ import com.won.smarketing.content.presentation.dto.PosterContentCreateRequest;
|
|||||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateResponse;
|
import com.won.smarketing.content.presentation.dto.PosterContentCreateResponse;
|
||||||
import com.won.smarketing.content.presentation.dto.PosterContentSaveRequest;
|
import com.won.smarketing.content.presentation.dto.PosterContentSaveRequest;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -25,10 +27,14 @@ import java.util.List;
|
|||||||
* 홍보 포스터 생성 및 저장 기능 구현
|
* 홍보 포스터 생성 및 저장 기능 구현
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public class PosterContentService implements PosterContentUseCase {
|
public class PosterContentService implements PosterContentUseCase {
|
||||||
|
|
||||||
|
@Value("${azure.storage.container.poster-images:poster-images}")
|
||||||
|
private String posterImageContainer;
|
||||||
|
|
||||||
private final ContentRepository contentRepository;
|
private final ContentRepository contentRepository;
|
||||||
private final AiPosterGenerator aiPosterGenerator;
|
private final AiPosterGenerator aiPosterGenerator;
|
||||||
private final BlobStorageService blobStorageService;
|
private final BlobStorageService blobStorageService;
|
||||||
@ -42,11 +48,11 @@ public class PosterContentService implements PosterContentUseCase {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public PosterContentCreateResponse generatePosterContent(List<MultipartFile> images, PosterContentCreateRequest request) {
|
public PosterContentCreateResponse generatePosterContent(List<MultipartFile> images, PosterContentCreateRequest request) {
|
||||||
|
log.info("지점1-1");
|
||||||
// 1. 이미지 blob storage에 저장하고 request 저장
|
// 1. 이미지 blob storage에 저장하고 request 저장
|
||||||
List<String> imageUrls = blobStorageService.uploadImage(images, "poster-content-original");
|
List<String> imageUrls = blobStorageService.uploadImage(images, posterImageContainer);
|
||||||
request.setImages(imageUrls);
|
request.setImages(imageUrls);
|
||||||
|
log.info("지점2-1");
|
||||||
// 2. AI 요청
|
// 2. AI 요청
|
||||||
String generatedPoster = aiPosterGenerator.generatePoster(request);
|
String generatedPoster = aiPosterGenerator.generatePoster(request);
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ public class SnsContentService implements SnsContentUseCase {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request, List<MultipartFile> files) {
|
public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request, List<MultipartFile> files) {
|
||||||
//파일들 주소 가져옴
|
//파일들 주소 가져옴
|
||||||
List<String> urls = blobStorageService.uploadImage(files);
|
List<String> urls = blobStorageService.uploadImage(files, "containerName");
|
||||||
request.setImages(urls);
|
request.setImages(urls);
|
||||||
|
|
||||||
// AI를 사용하여 SNS 콘텐츠 생성
|
// AI를 사용하여 SNS 콘텐츠 생성
|
||||||
|
|||||||
@ -17,7 +17,7 @@ public interface BlobStorageService {
|
|||||||
* @param file 업로드할 파일
|
* @param file 업로드할 파일
|
||||||
* @return 업로드된 파일의 URL
|
* @return 업로드된 파일의 URL
|
||||||
*/
|
*/
|
||||||
List<String> uploadImage(List<MultipartFile> file);
|
List<String> uploadImage(List<MultipartFile> file, String containerName);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -34,12 +34,6 @@ public class BlobStorageServiceImpl implements BlobStorageService {
|
|||||||
|
|
||||||
private final BlobServiceClient blobServiceClient;
|
private final BlobServiceClient blobServiceClient;
|
||||||
|
|
||||||
@Value("${azure.storage.container.poster-images:poster-images}")
|
|
||||||
private String posterImageContainer;
|
|
||||||
|
|
||||||
@Value("${azure.storage.container.content-images:content-images}")
|
|
||||||
private String contentImageContainer;
|
|
||||||
|
|
||||||
@Value("${azure.storage.max-file-size:10485760}") // 10MB
|
@Value("${azure.storage.max-file-size:10485760}") // 10MB
|
||||||
private long maxFileSize;
|
private long maxFileSize;
|
||||||
|
|
||||||
@ -60,7 +54,7 @@ public class BlobStorageServiceImpl implements BlobStorageService {
|
|||||||
* @return 업로드된 파일의 URL
|
* @return 업로드된 파일의 URL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> uploadImage(List<MultipartFile> files) {
|
public List<String> uploadImage(List<MultipartFile> files, String containerName) {
|
||||||
// 파일 유효성 검증
|
// 파일 유효성 검증
|
||||||
validateImageFile(files);
|
validateImageFile(files);
|
||||||
List<String> urls = new ArrayList<>();
|
List<String> urls = new ArrayList<>();
|
||||||
@ -70,10 +64,10 @@ public class BlobStorageServiceImpl implements BlobStorageService {
|
|||||||
for(MultipartFile file : files) {
|
for(MultipartFile file : files) {
|
||||||
String fileName = generateMenuImageFileName(file.getOriginalFilename());
|
String fileName = generateMenuImageFileName(file.getOriginalFilename());
|
||||||
|
|
||||||
ensureContainerExists(posterImageContainer);
|
ensureContainerExists(containerName);
|
||||||
|
|
||||||
// Blob 클라이언트 생성
|
// Blob 클라이언트 생성
|
||||||
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(posterImageContainer);
|
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
|
||||||
BlobClient blobClient = containerClient.getBlobClient(fileName);
|
BlobClient blobClient = containerClient.getBlobClient(fileName);
|
||||||
|
|
||||||
// 파일 업로드 (간단한 방식)
|
// 파일 업로드 (간단한 방식)
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.won.smarketing.content.presentation.controller;
|
package com.won.smarketing.content.presentation.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.won.smarketing.common.dto.ApiResponse;
|
import com.won.smarketing.common.dto.ApiResponse;
|
||||||
import com.won.smarketing.content.application.usecase.ContentQueryUseCase;
|
import com.won.smarketing.content.application.usecase.ContentQueryUseCase;
|
||||||
import com.won.smarketing.content.application.usecase.PosterContentUseCase;
|
import com.won.smarketing.content.application.usecase.PosterContentUseCase;
|
||||||
@ -11,6 +13,7 @@ import io.swagger.v3.oas.annotations.media.Content;
|
|||||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -25,6 +28,7 @@ import java.util.List;
|
|||||||
* SNS 콘텐츠 생성, 포스터 생성, 콘텐츠 관리 기능 제공
|
* SNS 콘텐츠 생성, 포스터 생성, 콘텐츠 관리 기능 제공
|
||||||
*/
|
*/
|
||||||
@Tag(name = "마케팅 콘텐츠 관리", description = "AI 기반 마케팅 콘텐츠 생성 및 관리 API")
|
@Tag(name = "마케팅 콘텐츠 관리", description = "AI 기반 마케팅 콘텐츠 생성 및 관리 API")
|
||||||
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/content")
|
@RequestMapping("/api/content")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -33,6 +37,7 @@ public class ContentController {
|
|||||||
private final SnsContentUseCase snsContentUseCase;
|
private final SnsContentUseCase snsContentUseCase;
|
||||||
private final PosterContentUseCase posterContentUseCase;
|
private final PosterContentUseCase posterContentUseCase;
|
||||||
private final ContentQueryUseCase contentQueryUseCase;
|
private final ContentQueryUseCase contentQueryUseCase;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SNS 게시물 생성
|
* SNS 게시물 생성
|
||||||
@ -70,28 +75,12 @@ public class ContentController {
|
|||||||
@Operation(summary = "홍보 포스터 생성", description = "AI를 활용하여 홍보 포스터를 생성합니다.")
|
@Operation(summary = "홍보 포스터 생성", description = "AI를 활용하여 홍보 포스터를 생성합니다.")
|
||||||
@PostMapping(value = "/poster/generate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
@PostMapping(value = "/poster/generate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
public ResponseEntity<ApiResponse<PosterContentCreateResponse>> generatePosterContent(
|
public ResponseEntity<ApiResponse<PosterContentCreateResponse>> generatePosterContent(
|
||||||
@Parameter(
|
@Parameter(content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE))
|
||||||
description = "참고할 이미지 파일들 (선택사항, 최대 5개)",
|
|
||||||
required = false,
|
|
||||||
content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
||||||
)
|
|
||||||
@RequestPart(value = "images", required = false) List<MultipartFile> images,
|
@RequestPart(value = "images", required = false) List<MultipartFile> images,
|
||||||
@Parameter(
|
@RequestPart("request") String requestJson) throws JsonProcessingException {
|
||||||
description = "포스터 생성 요청 정보",
|
|
||||||
required = true,
|
// JSON 파싱
|
||||||
example = """
|
PosterContentCreateRequest request = objectMapper.readValue(requestJson, PosterContentCreateRequest.class);
|
||||||
{
|
|
||||||
"title": "신메뉴 출시 이벤트",
|
|
||||||
"category": "이벤트",
|
|
||||||
"requirement": "밝고 화사한 분위기로 만들어주세요",
|
|
||||||
"eventName": "아메리카노 할인 이벤트",
|
|
||||||
"startDate": "2024-01-15",
|
|
||||||
"endDate": "2024-01-31",
|
|
||||||
"photoStyle": "밝고 화사한"
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
@RequestPart(value = "request") @Valid PosterContentCreateRequest request) {
|
|
||||||
|
|
||||||
PosterContentCreateResponse response = posterContentUseCase.generatePosterContent(images, request);
|
PosterContentCreateResponse response = posterContentUseCase.generatePosterContent(images, request);
|
||||||
return ResponseEntity.ok(ApiResponse.success(response, "포스터 콘텐츠가 성공적으로 생성되었습니다."));
|
return ResponseEntity.ok(ApiResponse.success(response, "포스터 콘텐츠가 성공적으로 생성되었습니다."));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user