Skip to content

Commit

Permalink
feat: FastAPI 서버 api 호출을 통한 이미지 분류 기능 구현 (#98)
Browse files Browse the repository at this point in the history
* feat: Feign 클라이언트 요청의 헤더를 확인하여 Content-Type 헤더를 설정

* feat: 이미지 분류 요청, 응답 dto 생성

* feat: FastAPI 서버 URL 및 엔드포인트 상수 정의

* feat: FastAPI 서버와의 통신을 위한 Feign 클라이언트 설정

* feat: 이미지 분류 기능 구현

* fix: fastapi 서버 민감한 정보 .env 파일에 관리

* fix: 이미지 API 상위 파라미터 RequestMapping으로 수정

* feat: task definition에 .env 파일에 작성한 환경 변수 추가
  • Loading branch information
ht3064 authored Jun 30, 2024
1 parent 6bd8893 commit 96cbd13
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
package com.api.pickle.domain.image.api;

import com.api.pickle.domain.image.application.ImageService;
import com.api.pickle.domain.image.dto.request.ImageClassificationRequest;
import com.api.pickle.domain.image.dto.request.PresignedUrlRequest;
import com.api.pickle.domain.image.dto.response.ClassifiedImageResponse;
import com.api.pickle.domain.image.dto.response.PresignedUrlResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "이미지 API", description = "이미지 API입니다.")
@RestController
@RequiredArgsConstructor
@RequestMapping("/images")
public class ImageController {

private final ImageService imageService;

@Operation(summary = "이미지 Presigned URL 생성", description = "이미지 Presigned URL을 생성합니다.")
@PostMapping("/images/upload-url")
@PostMapping("/upload-url")
public PresignedUrlResponse imagePresignedUrlCreate(@RequestBody PresignedUrlRequest request) {
return imageService.createImagePresignedUrl(request);
}

@Operation(summary = "이미지 분류 결과", description = "이미지 분류 결과를 반환합니다.")
@PostMapping("/classify")
public ClassifiedImageResponse classifyImages(@RequestBody ImageClassificationRequest request) {
return imageService.classifyImages(request);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.api.pickle.domain.album.dao.AlbumRepository;
import com.api.pickle.domain.image.dao.ImageRepository;
import com.api.pickle.domain.image.dto.request.ImageClassificationRequest;
import com.api.pickle.domain.image.dto.request.PresignedUrlRequest;
import com.api.pickle.domain.image.dto.response.ClassifiedImageResponse;
import com.api.pickle.domain.image.dto.response.PresignedUrlResponse;
import com.api.pickle.domain.member.domain.Member;
import com.api.pickle.global.util.MemberUtil;
import com.api.pickle.infra.config.feign.ImageClassificationClient;
import com.api.pickle.infra.config.s3.S3Properties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -35,6 +38,7 @@ public class ImageService {
private final AmazonS3 amazonS3;
private final ImageRepository imageRepository;
private final AlbumRepository albumRepository;
private final ImageClassificationClient imageClassificationClient;

public PresignedUrlResponse createImagePresignedUrl(PresignedUrlRequest request) {
final Member member = memberUtil.getCurrentMember();
Expand Down Expand Up @@ -92,4 +96,8 @@ private Date getPresignedUrlExpiration() {

return expiration;
}

public ClassifiedImageResponse classifyImages(ImageClassificationRequest request) {
return imageClassificationClient.getClassifiedImages(request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.api.pickle.domain.image.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.List;

@AllArgsConstructor
@Getter
public class ImageClassificationRequest {

@Schema(description = "업로드 한 이미지 URL 리스트")
private List<String> imageUrls;

@Schema(description = "그룹 간 유사도 설정 (true: 강하게, false: 약하게)")
private Boolean strongClustering;

@Schema(description = "선명하지 않은 사진 제외 (true: 체크)")
private Boolean eyeClosing;

@Schema(description = "눈 감은 사진 제외 (true: 체크)")
private Boolean blurred;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.api.pickle.domain.image.dto.response;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@AllArgsConstructor
@NoArgsConstructor
@Getter
public class ClassifiedImageResponse {

private List<List<String>> groupedImages;
}
28 changes: 28 additions & 0 deletions src/main/java/com/api/pickle/global/config/feign/FeignConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.api.pickle.global.config.feign;

import feign.RequestInterceptor;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

@Configuration
@EnableFeignClients(basePackages = "com.api.pickle.infra.config.feign")
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return template -> {
String contentType = template.headers()
.getOrDefault("Content-Type", Collections.emptyList())
.stream()
.findFirst()
.orElse("");
if (contentType.equals("application/json")) {
template.header("Content-Type", "application/json;charset=utf-8");
} else {
template.header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
}
};
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.api.pickle.infra.config.fastapi;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "fastapi")
@Getter
@Setter
public class FastAPIProperties {
private String serverUrl;
private String endpoint;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.api.pickle.infra.config.feign;

import com.api.pickle.domain.image.dto.request.ImageClassificationRequest;
import com.api.pickle.domain.image.dto.response.ClassifiedImageResponse;
import com.api.pickle.global.config.feign.FeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient(
name = "imageClassificationClient",
url = "${fastapi.serverUrl}",
configuration = FeignConfig.class)
public interface ImageClassificationClient {
@PostMapping(value = "${fastapi.endpoint}")
ClassifiedImageResponse getClassifiedImages(@RequestBody ImageClassificationRequest request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import com.api.pickle.domain.auth.dto.response.KakaoTokenResponse;
import com.api.pickle.global.common.constants.SecurityConstants;
import com.api.pickle.global.config.feign.KakaoFeignConfig;
import com.api.pickle.global.config.feign.FeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient(
name = "kakaoLoginClient",
url = SecurityConstants.KAKAO_LOGIN_URL,
configuration = KakaoFeignConfig.class)
configuration = FeignConfig.class)
public interface KakaoLoginClient {
@PostMapping(value = SecurityConstants.KAKAO_LOGIN_ENDPOINT)
KakaoTokenResponse getToken(@RequestBody String KakaoTokenRequest);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.api.pickle.infra.config.properties;

import com.api.pickle.infra.config.fastapi.FastAPIProperties;
import com.api.pickle.infra.config.jwt.JwtProperties;
import com.api.pickle.infra.config.oauth.KakaoProperties;
import com.api.pickle.infra.config.redis.RedisProperties;
Expand All @@ -11,6 +12,8 @@
KakaoProperties.class,
JwtProperties.class,
S3Properties.class,
RedisProperties.class})
RedisProperties.class,
FastAPIProperties.class})
@Configuration
public class PropertiesConfig {}
public class PropertiesConfig {
}
3 changes: 3 additions & 0 deletions src/main/resources/application-fastapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fastapi:
serverUrl: ${FAST_API_SERVER_URL}
endpoint: ${FAST_API_SERVER_ENDPOINT}
2 changes: 2 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ spring:
- s3
- security
- redis
- fastapi
prod:
- s3
- security
- redis
- fastapi

management:
endpoints:
Expand Down
8 changes: 8 additions & 0 deletions task-definition.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@
{
"name": "AWS_SECRET_KEY",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-2:122971469363:secret:playauto/gmp-2dXhTZ:AWS_SECRET_KEY::"
},
{
"name": "FAST_API_SERVER_URL",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-2:122971469363:secret:playauto/gmp-2dXhTZ:FAST_API_SERVER_URL::"
},
{
"name": "FAST_API_SERVER_ENDPOINT",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-2:122971469363:secret:playauto/gmp-2dXhTZ:FAST_API_SERVER_ENDPOINT::"
}
],
"ulimits": [],
Expand Down

0 comments on commit 96cbd13

Please sign in to comment.