[FocusOnYou] 파일업로드 구현 - FastAPI
이 프로젝트의 시작에 앞서 클라이언트 단에서 파일을 업로드하는 부분부터 구현했다.
흐름은 우선 클라이언트가 파일(이미지와 비디오)을 업로드하면 해당 파일들을 S3 버킷으로 저장시키고자 했다.
파일을 API로 전달받기
FastAPI에서는 클라이언트가 업로드한 파일작업을 위해 File 클래스를 지원한다. 업로드된 파일을 File로 전달받기 위해서 우선 python-multipart 모듈을 설치해주어야한다. (업로드된 파일들은 form-data 형태로 전송된다고한다.)
pip install python-multipart
일반적으로 FastAPI에서 파일업로드는 bytes 자료형을 사용하는 것과 UploadFile 객체를 이용하는 것, 2가지 방법이 있다.
bytes를 사용하는 경우 파일의 전체 내용이 메모리에 저장되어 작은 파일을 다루는데에 적합하다고 한다.
사용자로부터 이미지파일과 비디오 파일, 총 2개의 파일을 업로드 받으므로 Uploadfile을 이용해 다음과 같이 처리해준다.
@app.post("/upload")
async def upload(face_name: str = Form(...), face_image: UploadFile = File(...), target_video: UploadFile = File(...)):
return {
"face_name": face_name,
"face_image_filename": face_image.filename,
"target_video_filename": target_video.filename
}
FastAPI 공식 Docs에서 설명하는 UploadFile의 Attribute와 Method는 다음과 같다.
이렇게 클라이언트가 업로드한 파일을 FastAPI까지 받아오는 구간을 완성할 수 있다.
S3 버킷으로 파일 업로드
S3 버킷으로 파일을 업로드 하기 위해 Python용 AWS SDK(boto3)를 import해 사용했다.
AWS의 모든 서비스는 API화되어있어 포맷에 맞춰 사용하기 간편하다. Code를 통해 AWS API를 사용하는 경우 반드시 공식 Docs를 참고하는 습관을 들이자.
Boto3 API 문서
import boto3
# s3 명령을 위한 client 선언
s3 = boto3.client("s3",aws_access_key_id=os.getenv("AWS_ACCESS_KEY"),aws_secret_access_key=os.getenv("AWS_SECRET_KEY"))
...
boto3는 버킷에 파일을 업로드하는 함수는 2가지를 제공한다.
upload_file과 upload_fileobj로, 두 함수 모두 기능 자체는 동일하나 입력받는 파일 객체 부분이 다르다.
upload_file은 '업로드할 파일이 저장된 경로'를 받는 반면, upload_fileobj는 '읽기가능한 file-like 객체'를 받는다.
s3.upload_file('/tmp/hello.txt', 'mybucket', 'hello.txt')
with open('filename', 'rb') as data:
s3.upload_fileobj(data, 'mybucket', 'mykey')
upload_file은 업로드 받은 파일을 서버단에서 1차적으로 저장을 시킨 후 그 경로를 넣어줘야하는 과정이 필요하다.
하지만 upload_fileobj는 이미 업로드된 파일 객체를 그대로 넣어주면 되므로 위에서 UploadFile로 구현한 상황에 도입하기 가장 적합한 것을 볼 수 있다.
@app.post("/upload")
async def upload(face_name: str = Form(...), face_image: UploadFile = File(...), target_video: UploadFile = File(...)):
...
job_id = str(uuid.uuid4())
image_object_name = f"face_image/{job_id}/{face_image.filename}"
target_video_object_name = f"target-video/{job_id}/{target_video.filename}"
try:
s3.upload_fileobj(
face_image.file,
S3_BUCKET_NAME,
image_object_name,
ExtraArgs={
"Metadata": {
"face_name": face_name
}
})
s3.upload_fileobj(target_video.file, S3_BUCKET_NAME, target_video_object_name)
다음으로 버킷으로 업로드된 파일을 Rekognition API를 이용해 처리하는 아키텍쳐를 작성해보도록 한다.