API 개발/API 개발 Project

API Project : (3) SNS 서비스 개발 (사진 포스팅 + 태그 자동 번역 기능)

신강희 2024. 5. 30. 18:07
728x90

< (3) SNS 서비스 개발

(사진 포스팅 + 태그 자동 번역 기능) >

 

# 사진 포스팅 기능 : 사진 1장 + 내용을 포스팅

- 사진 포스팅에 대한 CRUD 기능 있어야함!

- 생성된 태그는 자동 번역되어 출력되도록 설계

- 우선 사진 저장을 위해서 AWS S3에서 새로운 버킷 생성

 

# 화면 구성을보고 필요한 DB 설계

- 포스팅을 가져오는 API는 내친구들의 포스팅만!

- 다음처럼 Response가 오도록 설계 => postID, imgUrl, content, userId, email (DB 컬럼명은 헝가리안 표기법으로 사용하는게 작업에 용이함)

- 태그를 받아오기위한 DB도 필요!

 

# DB 생성까지 완료되었고, Postman을 실행시켜 API 리퀘스트 생성

- Headers도 Authorization로 토큰 사용할수 있도록 설정해 준다.

 

# Visual Studio Code에서 코드 작성!

- resources 폴더안에 posting.py라는 파일로 생성하여 작성

- AWS의 번역 API도 사용함 태그해석을 위해

 
from flask import request
from flask_jwt_extended import get_jwt_identity, jwt_required
from flask_restful import Resource

from mysql_connection import get_connection
from mysql.connector import Error

from datetime import datetime
import boto3
from config import Config

class PostingListResource(Resource) :
    # 포스팅하는 API
    @jwt_required()
    def post(self) :
       
        #1. 클라이언트로부터 데이터 받아온다.
        if 'image' not in request.files :
            return {'result' : 'fail' ,
                    'error' : '파일을 업로드 하세요.'}, 400
        if 'content' not in request.form :
            return {'result' : 'fail' ,
                    'error' : '내용을 작성하세요.'}, 400
       
        file = request.files['image']
        content = request.form['content']

        user_id = get_jwt_identity()

        #2. 사진을 S3에 업로드 한다.
        if file is None :
            return {'result' : 'fail' ,
                    'error' : '파일을 업로드 하세요.'}, 400
       
        if 'image' not in file.content_type :
            return {'result' : 'fail',
                    'error' : '이미지 파일만 업로드 가능합니다.'}, 400
       
        client = boto3.client('s3',
                    aws_access_key_id = Config.AWS_ACCESS_KEY,
                    aws_secret_access_key = Config.AWS_SECRET_ACCESS_KEY)
       
        # 파일 이름을 유니크하게 만들어줘야 한다.
        current_time = datetime.now()
        file_name = current_time.isoformat().replace(':','_') + str(user_id) + '.jpg'
        file.filename = file_name
       
        # 버킷을 만들어야 한다.
        try :
            client.upload_fileobj(file,
                                  Config.AWS_S3_BUCKET,
                                  file.filename,
                                  ExtraArgs = {'ACL' : 'public-read',
                                               'ContentType' : 'image/jpeg'})
        except Exception as e:
            return {'result' : 'fail',
                    'error' : str(e)}, 500

        #3. 업로드한 사진의 URL을 만든다.
        image_url = Config.AWS_FILE_URL + file.filename

        #3-2. rekognition 을 이용해서, object detection 하여,
        #     태그로 사용할 label 을 뽑는다.
        label_list = self.detect_labels(file.filename, Config.AWS_S3_BUCKET)

        label_str = ','.join(label_list)

        label_str = self.translate(label_str)

        label_list = label_str.split(', ')
       
        #4. DB에 userID, imageUrl, content를 저장한다.
        try :
            connection = get_connection()
            query = '''insert into posting
                        (userId, imageUrl, content)
                        values
                        (%s, %s, %s);'''
            record = (user_id, image_url, content)
            cursor = connection.cursor()
            cursor.execute(query, record)

            posting_id = cursor.lastrowid

            for label in label_list:
                # tag 테이블에, label이 있는지 확인해서,
                # 있으면 아이디를 가져오고, 없으면 인서트한 후에 아이디를 가져온다.
                query = '''select *
                        from tag
                        where name = %s;'''
                record = (label, )

                cursor = connection.cursor(dictionary=True)
                cursor.execute(query, record)

                result_list = cursor.fetchall()

                # 혹은 != 0 / 0이 아니면        
                if len(result_list) == 1 :
                    tag_id = result_list[0]['id']
                else :
                    query = '''insert into tag
                                (name)
                                values
                                (%s);'''
                    record = (label, )
                    cursor = connection.cursor()
                    cursor.execute(query, record)
                    tag_id = cursor.lastrowid

                # 위에 tagId를 posting_tag 테이블에, postingID 와 함께 넣어준다.
                query = '''insert into posting_tag
                            (postingId, tagId)
                            values
                            (%s, %s);'''
               
                record = (posting_id, tag_id)
                cursor = connection.cursor()
                cursor.execute(query, record)

            connection.commit()

            cursor.close()
            connection.close()

        except Error as e :
            if cursor is not None:
                cursor.close()
            if connection is not None:
                connection.close()
            return {'result' : 'fail',
                    'errer' : str(e)}, 500

        #5. 클라이언트에 json으로 응답한다.
       
        return {'result' : '업로드가 완료되었습니다.',
                'url' : Config.AWS_FILE_URL + file_name}
   
    # AWS 레코그니션 사용을 위한 함수
    def detect_labels(self, photo, bucket):

        client = boto3.client('rekognition',
                     'ap-northeast-2',
                     aws_access_key_id = Config.AWS_ACCESS_KEY,
                     aws_secret_access_key = Config.AWS_SECRET_ACCESS_KEY)

        response = client.detect_labels(Image={'S3Object':{'Bucket':bucket,'Name':photo}},
        MaxLabels=10,
        # Uncomment to use image properties and filtration settings
        #Features=["GENERAL_LABELS", "IMAGE_PROPERTIES"],
        #Settings={"GeneralLabels": {"LabelInclusionFilters":["Cat"]},
        # "ImageProperties": {"MaxDominantColors":10}}
        )

        print('Detected labels for ' + photo)
        print()
        print(response['Labels'])
       
        label_list = []

        for label in response['Labels']:
            print("Label: " + label['Name'])
            label_list.append(label['Name'])
       
        return label_list
   
    # 번역 API 사용을 위한 함수
    def translate(self, text) :
        client = boto3.client(service_name='translate',
                              region_name='ap-northeast-2',
                              aws_access_key_id = Config.AWS_TRANSLATE_ACCESS_KEY,
                              aws_secret_access_key = Config.AWS_TRANSLATE_SECRET_ACCESS_KEY)

        result = client.translate_text(Text=text,
                                       SourceLanguageCode="en",
                                       TargetLanguageCode="ko")
        print('TranslatedText: ' + result.get('TranslatedText'))
        print('SourceLanguageCode: ' + result.get('SourceLanguageCode'))
        print('TargetLanguageCode: ' + result.get('TargetLanguageCode'))

        return result.get('TranslatedText')

 

# app.py에도 연결 코드 작성

import serverless_wsgi

from flask import Flask
from flask_restful import Api

from flask_jwt_extended import JWTManager
from config import Config

from resources.follow import FollowResource
from resources.like import LikeResource
from resources.posting import PostingListResource
from resources.user import UserLoginResource, UserLogoutResource, UserRegisterResource, jwt_blacklist

app = Flask(__name__)

# 환경변수 셋팅
app.config.from_object(Config)

# JWT 매니저 초기화
jwt = JWTManager(app)

# 로그아웃된 토큰으로 요청하는 경우, 처리하는 함수 작성
@jwt.token_in_blocklist_loader
def check_if_token_is_revoked(jwt_header, jwt_payload) :
    jti = jwt_payload['jti']
    return jti in jwt_blacklist

api = Api(app)

# 경로와 리소스를 연결하는 코드 작성
api.add_resource( UserRegisterResource , '/user/register')
api.add_resource( UserLoginResource , '/user/login')
api.add_resource( UserLogoutResource , '/user/logout')

api.add_resource( PostingListResource , '/posting')
 
def handler(event, context) :
    return serverless_wsgi.handle_request(app, event, context)

if __name__ == '__main__':
    app.run()
 

 

# Postman 에서 send보내고 링크로 이미지 확인 및 VSC에서 자동 번역 문구 출력도 확인

 

다음 게시글로 계속~!

 

반응형