✍️ 개발 기록

[👀 Owing] OpenAI 이미지 생성 후 S3에 안전하게 저장하기 (feat. AWS S3에 Base64 이미지 저장)

ming412 2024. 11. 8. 10:14

response format을 url로 설정 후 이미지 생성 시 OpenAI의 url이 나온는데, 이는 우리의 리소스가 아니기 때문에 해당 url을 저장해도 될까? 라는 고민이 있었다. 결론적으로, 외부에서 관리되는 OpenAI의 URL을 그대로 사용하면 리소스 관리 측면에서 여러 제약이 생긴다는 것이다.

OpenAI 서버가 만약 URL을 변경하거나 만료 정책을 적용하면, 서비스 안정성에 영향을 줄 수 있다.

 

따라서 이미지 자체를 우리의 S3에 업로드한 뒤, 생성되는 객체 자체의 url을 데이터베이스에 저장하기로 했다.

 

현재 응답 결과 - OpenAI의 주소로 url이 생성되는 모습

 

이미지를 Base64 문자열로 인코딩

순서는 다음과 같다.

1. AI 요청에 대한 응답으로 Base64로 인코딩 된 문자열을 받는다. (response options 변경)
2. Base64 인코딩 문자열을 디코딩하여 바이트 배열로 변환한다.
3. 이를 S3에 파일 형태로 업로드한다.

 

1. AI 요청에 대한 응답 옵션 변경

변경 전

private static OpenAiImageOptions imageOptions() {
    return OpenAiImageOptions.builder()
        .withModel(OpenAiImageApi.ImageModel.DALL_E_3.getValue())
        .withResponseFormat("url")
        ...
}

변경 후

private static OpenAiImageOptions imageOptions() {
    return OpenAiImageOptions.builder()
        .withModel(OpenAiImageApi.ImageModel.DALL_E_3.getValue())
        .withResponseFormat("b64_json")
        ...
}

 

base64로 인코딩 된 문자열을 반환하는 모습

 

2&3. Base64 인코딩 문자열을 디코딩하여 바이트 배열로 변환 후, S3에 파일 형태로 업로드한다.

`S3Service.java`

/* Base64 이미지를 S3에 업로드  */
public String uploadBase64ImageToS3(AiImageUploadRequest aiImageUploadRequest) {

    String fileName = FileNameUtils.buildFileName("sample.png");

    // Base64 문자열을 바이트 배열로 디코딩
    byte[] decodedBytes = Base64.getDecoder().decode(aiImageUploadRequest.b64Json());

    // 바이트 배열을 InputStream으로 변환
    InputStream inputStream = new ByteArrayInputStream(decodedBytes);

    return uploadFileToS3(fileName, inputStream, decodedBytes.length);
}

private String uploadFileToS3(String fileName, InputStream inputStream, long contentLength) {

		UUID randomUUID = UUID.randomUUID();

		PutObjectRequest putObjectRequest = PutObjectRequest.builder()
			.bucket(bucketName)
			.key(DIRECTORY_PATH + randomUUID + fileName)
			.contentType(getContentType(fileName))
			.build();

		s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, contentLength));

		GetUrlRequest getUrlRequest = GetUrlRequest.builder()
			.bucket(bucketName)
			.key(DIRECTORY_PATH + randomUUID + fileName)
			.build();

		return s3Client.utilities().getUrl(getUrlRequest).toString();

	}

`AiImageUploadRequest.java`

public record AiImageUploadRequest (String b64Json) 
{
}

 

3. 응답 결과

이제 외부 리소스가 아닌, 우리의 s3 버킷에 있는 객체 url을 반환한다.

S3 업로드 후 객체 자체의 url을 반환하는 모습

 

 

 

참고

https://velog.io/@banjjoknim/byte-%EB%A1%9C-S3%EC%97%90-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%97%85%EB%A1%9C%EB%93%9C%ED%95%98%EA%B8%B0