Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework:spring-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'


Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/school/mohitto/config/WebClientFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class WebClientFactory {

public WebClient create(String baseUrl) {
return webClientBuilder
.codecs(configurer -> configurer.defaultCodecs()
.maxInMemorySize(10 * 1024 * 1024))
.baseUrl(baseUrl)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.school.mohitto.controller;

import com.school.mohitto.dto.requestDTO.ChangeFaceSimulationRequest;
import com.school.mohitto.dto.requestDTO.SimulationRequest;
import com.school.mohitto.dto.responseDTO.ChangeFaceSimulationResponse;
import com.school.mohitto.dto.responseDTO.RecommandResponse;
import com.school.mohitto.service.SimulationService;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand All @@ -27,4 +29,13 @@ public RecommandResponse getRecommand(
) throws IOException {
return simulationService.extractFaceAndRecommand(multipartFile,simulationRequest);
}

@PostMapping(value = "/transfer-face", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ChangeFaceSimulationResponse changeFaceInSimulationService(
@RequestPart(value = "image", required = true)
MultipartFile multipartFile,
@RequestPart(value = "data") ChangeFaceSimulationRequest modelImageId
) throws IOException {
return simulationService.changeFaceInSimulationService(multipartFile, modelImageId);
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/school/mohitto/domain/CreatedImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -20,6 +21,12 @@ public class CreatedImage extends BaseTimeEntity {
@JoinColumn(name = "hair_id", nullable = true)
private Hair hair;


@Column(name = "url", length = 255)
private String createdImageUrl;

@Builder
public CreatedImage(String createdImageUrl) {
this.createdImageUrl = createdImageUrl;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.school.mohitto.dto.requestDTO;

public record ChangeFaceRequest(
String user_image_url,
String ref_image_url
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.school.mohitto.dto.requestDTO;


public record ChangeFaceSimulationRequest(
Long modelImageId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.school.mohitto.dto.responseDTO;

import org.springframework.web.multipart.MultipartFile;

public record ChangeFaceResponse(
MultipartFile multipartFile
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.school.mohitto.dto.responseDTO;

public record ChangeFaceSimulationResponse(
String resultImageUrl
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.school.mohitto.repository;

import com.school.mohitto.domain.ModelImage;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ModelImageRepository extends JpaRepository<ModelImage, Long> {
}
55 changes: 52 additions & 3 deletions src/main/java/com/school/mohitto/service/SimulationService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,32 @@
import com.school.mohitto.aws.s3.S3Uploader;
import com.school.mohitto.config.WebClientFactory;
import com.school.mohitto.domain.Diagnosis;
import com.school.mohitto.domain.ModelImage;
import com.school.mohitto.domain.UploadImage;
import com.school.mohitto.dto.requestDTO.FaceExtractRequest;
import com.school.mohitto.dto.requestDTO.RecommandRequest;
import com.school.mohitto.dto.requestDTO.SimulationRequest;
import com.school.mohitto.dto.requestDTO.*;
import com.school.mohitto.dto.responseDTO.ChangeFaceSimulationResponse;
import com.school.mohitto.dto.responseDTO.FaceExtractResponse;
import com.school.mohitto.dto.responseDTO.RecommandResponse;
import com.school.mohitto.exception.CustomException;
import com.school.mohitto.exception.code.ErrorCode;
import com.school.mohitto.fastapi.FastapiProperties;
import com.school.mohitto.repository.DiagnosisRepository;
import com.school.mohitto.repository.DiagnosisRepositorys.*;
import com.school.mohitto.repository.ModelImageRepository;
import com.school.mohitto.repository.UploadImageRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Slf4j
Expand All @@ -42,6 +47,8 @@ public class SimulationService {
private final DiagnosisMoodRepository diagnosisMoodRepository;
private final DiagnosisRepository diagnosisRepository;
private final UploadImageRepository uploadImageRepository;
private final ModelImageRepository modelImageRepository;


private final WebClientFactory webClientFactory;
private final S3Uploader s3Uploader;
Expand Down Expand Up @@ -183,5 +190,47 @@ private RecommandResponse generateHairStyle(RecommandRequest recommandRequest) {
}
return response;
}

public ChangeFaceSimulationResponse changeFaceInSimulationService(
MultipartFile multipartFile,
ChangeFaceSimulationRequest inputFaceRequest) throws IOException {
String user_image_url = s3Uploader.upload(multipartFile, "face");

ModelImage modelImage = modelImageRepository.findById(inputFaceRequest.modelImageId())
.orElseThrow(() -> new CustomException(ErrorCode.HAIR_NOT_FOUND));

ChangeFaceRequest changeFaceRequest = new ChangeFaceRequest(user_image_url, modelImage.getUploadImageUrl());

Resource response = webClientFactory.create(fastapiProperties.hairTransfer()).post()
.uri("/simulate")
.accept(MediaType.IMAGE_PNG)
.bodyValue(changeFaceRequest)
.retrieve()
.onStatus(HttpStatusCode::isError, clientResponse ->
clientResponse.bodyToMono(String.class).flatMap(error ->
Mono.error(new RuntimeException("시뮬레이션 모델 오류: " + error))
)
)
.bodyToMono(Resource.class)
.block();

MultipartFile file = convertResourceToMultipartFile(response);
String result_image_url = s3Uploader.upload(file, "result");
return new ChangeFaceSimulationResponse(result_image_url);
}

private MultipartFile convertResourceToMultipartFile(Resource resource) throws IOException {
String originalFileName = resource.getFilename(); // 예: "123_result.png"
String contentType = "image/jpg"; // 필요시 확장자 따라 변경 가능

try (InputStream inputStream = resource.getInputStream()) {
return new MockMultipartFile(
"file", // field name (multipart 필드명)
originalFileName, // 클라이언트에서 올라온 파일명
contentType, // Content-Type
inputStream // 파일 데이터
);
}
}
}