FAST API

2024. 12. 13. 10:57LLM(Large Language Model)의 기초

1.FAST API란?
* FastAPI는 Python 기반의 웹 프레임워크로, 주로 API를 빠르게 개발하기 위해 설계되었습니다.
* FastAPI는 자동으로 생성되는 OpenAPI 문서(Swagger UI)를 통해 API의 사용성과 테스트를 쉽게 할 수 있으며, 데이터 유효성 검사와 타입 힌트를 활용한 코드 자동완성 및 오류 방지를 지원합니다.
* 특히, 비동기 처리를 활용하여 속도가 중요한 대규모 애플리케이션 개발에 적합하며, RESTful API와 GraphQL 같은 현대적 웹 API 개발에 유용합니다.

*타입 힌팅(Type Hints)
 * 타입 힌팅(Type Hints)은 프로그래밍 언어에서 변수, 함수 매개변수, 함수 반환값 등에 대한 데이터 타입 정보를 코드에 명시적으로 제공하는 기술입니다. 
 * Python 3.5 이상에서 도입된 기능으로, 코드의 가독성을 높이고 프로그램의 안정성을 강화하는 데 도움이 됩니다.
 
2. Fast API vs Flask vs Django의 장단점
 
FastApi
장점
* FastAPI는 최신 Python 기반 프레임워크로 빠른 성능과 사용하기 쉬운 API로 유명합니다. 
* 비동기 프로그래밍을 지원하므로 실시간 애플리케이션 구축에 적합합니다. 또한 자동 API 문서화 및 유효성 검사를 제공하여 개발자의 시간과 노력을 절약합니다.

단점
* FastAPI는 비교적 새로운 프레임워크이며 기존 프레임워크에 비해 커뮤니티 지원 및 리소스가 많지 않을 수 있습니다. 또한 비동기 프로그래밍을 처음 접하는 개발자를 위한 학습 곡선도 있습니다.
 
활용도
* FastAPI는 특히 데이터 집약적인 애플리케이션을 위한 실시간 및 고성능 API 구축에 적합합니다.
 
Django
장점
* Django는 웹 애플리케이션 개발에 널리 사용되는 성숙한 Python 기반 프레임워크입니다. 
* 인증, 관리자 패널 및 ORM과 같은 많은 기본 기능을 제공합니다. 또한 지원 및 리소스를 제공하는 크고 활동적인 커뮤니티가 있습니다.

단점
* Django는 복잡할 수 있으며 설정하려면 상당한 구성이 필요합니다.
* 소규모 프로젝트나 경량 API 구축에는 적합하지 않을 수도 있습니다.

활용
* Django는 웹 애플리케이션, 특히 콘텐츠 기반 웹사이트, 전자상거래 플랫폼 및 소셜 미디어 플랫폼을 구축하는 데 널리 사용됩니다.
 
Flask
장점
* Flask는 배우고 사용하기 쉬운 경량 Python 기반 프레임워크입니다. 
* 유연성을 제공하고 개발자가 모듈식 및 확장 가능한 방식으로 웹 애플리케이션을 구축할 수 있도록 합니다. 또한 사용자 정의가 가능하고 소규모 프로젝트를 구축하는 데 적합합니다.

단점
*Flask는 다른 프레임워크에 비해 기본 제공 기능이 적기 때문에 개발자가 구현하는 데 더 많은 노력과 시간이 필요할 수 있습니다.
* 또한 대규모 웹 애플리케이션을 구축하는 데 적합하지 않을 수도 있습니다.

활용
Flask는 개인 웹 사이트, 간단한 API 및 내부 대시보드와 같은 소규모 웹 애플리케이션 및 프로토타입을 구축하는 데 적합합니다.
 
요약
* FastAPI는 실시간 및 고성능 API를 구축하는 데 적합한 현대적이고 빠른 프레임워크이고, Django는 복잡한 웹 애플리케이션을 구축하는 데 적합한 성숙한 프레임워크이며, Flask는 소규모 웹 애플리케이션 및 프로토타입을 구축하는 데 적합한 가볍고 유연한 프레임워크입니다. 
* 그들 사이의 선택은 개발 팀의 기술과 경험뿐만 아니라 프로젝트의 특정 요구 사항과 요구 사항에 따라 다릅니다.
 
3. 비동기 프로그래밍
* 비동기 프로그래밍은 코드가 병렬적으로 실행되는 것처럼 보이게 하는 프로그래밍 방식입니다.
* 이는 특히 I/O 작업(네트워크 요청, 파일 읽기/쓰기 등)에서 시간을 절약하고 프로그램의 성능을 최적화하는 데 유용합니다.
 
3-1. 동기(Synchronous)
* 작업이 순차적으로 실행됩니다.
* 하나의 작업이 끝날 때까지 다음 작업이 대기합니다.
예시 1)

예시) 
# def 키워드로 선언하는 모든 함수는 파이썬에서 기본적으로 동기 방식으로 동작
def do_sync():
    print("do_sync")
    
do_sync()
-->
do_sync

 
3-2. 비동기(Asynchronous)
* 작업이 독립적으로 실행되며, 대기 시간이 발생하면 다른 작업을 처리할 수 있습니다
예시)

import asyncio

async def do_async():
    print("do_async")

# 비동기 함수는 일반적으로 async 로 선언된 다른 비동기 함수 내에서 await 키워드를 붙여서 호출해야 함
# await 는 비동기 함수나 코루틴의 실행을 일시 중단하고 다른 작업을 처리할 수 있도록 함
async def main_async():
    await do_async()

# async 로 선언되지 않은 일반 동기 함수 내에서 비동기 함수를 호출하려면 asyncio.run 을 이용
asyncio.run(main_async())
#-->
#do_async

 
 
※ 코루틴(Coroutine)
* 파이썬에서 비동기 프로그래밍을 구현하기 위해 사용하는 특별한 형태의 함수입니다.
* 일반 함수와는 달리, 코루틴은 실행 중에 멈췄다가 다시 실행을 재개할 수 있습니다.
* 이를 통해 작업을 효율적으로 분할하고 비동기 처리를 가능하게 합니다.
 
예시 3)

import asyncio

async def task(name, duration):
    print(f"{name} 시작")
    await asyncio.sleep(duration)
    print(f"{name} 완료")

async def main():
    await asyncio.gather(
        task("작업 1", 2),
        task("작업 2", 3),
        task("작업 3", 1)
    )

asyncio.run(main())
#-->
#작업 1 시작
#작업 2 시작
#작업 3 시작
#작업 3 완료
#작업 1 완료
#작업 2 완료

 
4. 비동기 프로그래밍을 사용하는 이유
4-1. 
* 응답성(Responsiveness): 비동기 작업은 여러 작업을 동시에 처리하고, 작업이 완료되기를 기다리는 동안 다른 작업을 처리할 수 있습니다. 
- 이로써 프로그램의 응답성이 향상되고, 장기 실행 작업이 다른 작업을 차단하지 않도록 할 수 있습니다. 
- 예를 들어, 네트워크 요청이나 데이터베이스 조회 등의 I/O 작업을 비동기로 처리하면, 다른 작업을 수행하면서 응답을 기다릴 필요가 없어집니다.


4-2. 
* 확장성(Scalability): 비동기 프로그래밍은 많은 수의 동시 요청 또는 작업을 처리할 때 유용합니다.
- 여러 작업을 동시에 실행하고 완료될 때까지 기다리지 않아도 되므로, 처리량과 처리 속도를 향상할 수 있습니다.
- 이는 웹 서버, 네트워크 서비스, 데이터 파이프라인 등과 같은 시스템의 확장성을 향상하는 데 도움이 됩니다.

4-3. 
* 자원 효율성(Resource Efficiency): 비동기 작업은 작업의 대기 시간 동안 자원을 효율적으로 활용할 수 있습니다.
- 대기 시간 동안 CPU나 메모리 등의 자원을 다른 작업에 할당하여 더 많은 작업을 처리할 수 있습니다.
- 이는 시스템의 자원 이용률을 높이고, 전체적인 성능을 향상할 수 있습니다.


4-4. 
* 병렬성(Concurrency): 비동기 프로그래밍은 병렬적인 작업을 효율적으로 처리할 수 있는 방법을 제공합니다.
- 여러 작업이 동시에 실행될 수 있으며, 이는 멀티코어 프로세서를 활용하여 작업을 분산 처리할 수 있음을 의미합니다.
- 이를 통해 병렬성을 높여 전체적인 처리 시간을 단축시킬 수 있습니다.
 
5. FASTAPI
* FastAPI 애플리케이션을 실행하기 위해 uvicorn이라는 ASGI 서버가 필요합니다.
* Uvicorn은 Python으로 작성된 가볍고 빠른 웹 서버로, 비동기 웹 애플리케이션과 API를 실행하는 데 사용됩니다. 
* 특히 FastAPI와 잘 어울리며, WebSocket과 HTTP/2 같은 최신 웹 기술을 지원합니다.
* 개발할 때는 자동 리로드 기능으로 편리하게 작업할 수 있고, 운영 환경에서는 다중 프로세스로 높은 성능을 제공합니다.
 
6. uvicorn [standard]
1. 이 패키지는 uvicorn에 기본적으로 포함된 기능 외에도 추가적인 표준 미들웨어를 포함합니다.
2. 표준 미들웨어는 보안, 로깅 및 기타 서버 관련 기능을 추가하는 데 도움이 됩니다.
3. 예를 들어, Gzip 압축, CORS(Cross-Origin Resource Sharing) 지원 등이 기본적으로 포함되어 있습니다.

uvicorn 설치
    pip install "uvicorn[standard]"

 
 
FAST API 사용법
 
1. 우선 venv를 생성한다.
python -m venv venv 생성
venv/Scripts 가서 activate.bat을 실행
 
2. FAST API  설치

pip install fastapi

 
uvicorn
1. 기본적으로 필요한 최소한의 기능만을 제공하는 패키지입니다.
2. uvicorn [standard]에 비해 미들웨어가 적고, 기본적인 서버 기능만을 제공합니다.


※ ASGI 서버
* ASGI 서버는 Python에서 비동기 웹 애플리케이션을 실행할 수 있게 해주는 서버입니다.
* 기존의 WSGI 서버는 동작이 느리고 실시간 기능(WebSocket, HTTP/2 등)을 지원하지 않았지만, ASGI 서버는 비동기로 동작해 더 빠르고 실시간 데이터 처리도 가능합니다. 
* FastAPI 같은 최신 웹 프레임워크가 ASGI 서버와 잘 어울리며, 대표적인 서버로 Uvicorn과 Daphne가 있습니다.
* 이를 통해 많은 요청을 동시에 처리하고, 실시간 기능이 필요한 앱을 쉽게 만들 수 있습니다.
http://127.0.0.1:8000/docs (포스트맨 대신 실해해 줘서 편하다.)
 
 
 
uvicorn 설치

pip install "uvicorn[standard]"

 
http://127.0.0.1:8000/docs에 들어가면 PostMan 대신에 실행해 준다.
 
main.py 생성 후 작성해 주면 이렇게 돌아간다.

from fastapi import FastAPI

users = {
    0: {"userid": "apple", "name": "김사과"},
    1: {"userid": "banana", "name": "반하나"},
    2: {"userid": "orange", "name": "오렌지"}
}

app = FastAPI()

# http://127.0.0.1:8000/users/0
@app.get("/users/{id}")
def find_user(id: int):
    user = users[id]
    return user

 
4. FAST API 실행

try it out 누르고
아이디 1이라치고 Excute를 누르면

 

이부분이 나온다

- FastAPI 애플리케이션을 실행하기 위해 uvicorn이라는 ASGI 서버가 필요합니다. Uvicorn은 Python으로 작성된 가볍고 빠른 웹 서버로, 비동기 웹 애플리케이션과 API를 실행하는 데 사용됩니다. 
특히 FastAPI와 잘 어울리며, WebSocket과 HTTP/2 같은 최신 웹 기술을 지원합니다. 개발할 때는 자동 리로드 기능으로 편리하게 작업할 수 있고, 운영 환경에서는 다중 프로세스로 높은 성능을 제공합니다
 
그러면 제대로 받아온 걸 확인해 볼 수 있다.
 
2. Gradiod 와 FAST API 연결하는법

 

1. app.py 파일

#app.py 파일
import gradio as gr
import requests
# 광고 문구 생성 함수
def generate_ad(product_name, details, options):
    url = "http://127.0.0.1:8000/create_ad"
    try:
        response = requests.post(
            url,
            json={
                "product_name":product_name,
                "details":details,
                "tone_and_manner":", ".join(options)
            }
        )
        if response.status_code == 200:
            data = response.json()
            ad = data["ad"]
            return ad
        else:
            return "광고 문구 생성 실패!"
    except:
        return "서버 연결 실패"
# Gradio 화면 구성
def main():
    with gr.Blocks() as demo:
        gr.Markdown("광고 문구를 생성해주는 서비스 앱")
        with gr.Row():
            product_name = gr.Textbox(label="제품 이름", placeholder="제품 이름을 입력하세요")
            details = gr.Textbox(label="주요 내용", placeholder="제품의 주요 내용을 입력하세요")
        options = gr.CheckboxGroup(
            label="광고 문구의 느낌",
            choices=["기본", "재밌게", "차분하게", "과장스럽게", "참신하게", "고급스럽게", "센스있게", "가볍게"], value=["기본"]
        )
        generate_button = gr.Button("문구 생성하기")
        ad_output = gr.Textbox(label="생성된 광고 문구", interactive=False)
        generate_button.click(
            generate_ad,
            inputs=[product_name, details, options],
            outputs=[ad_output]
        )
    return demo
# 실행
if __name__ == "__main__":
    app = main()
    app.launch()

-->

설명글 추가(참고)

import gradio as gr  # Gradio 라이브러리를 가져와 웹 기반 인터페이스를 생성하는 데 사용
import requests      # HTTP 요청을 보내기 위한 requests 라이브러리

# 광고 문구 생성 함수
def generate_ad(product_name, details, options):
    """
    광고 문구를 생성하기 위해 서버에 요청을 보내고 결과를 반환하는 함수입니다.
    
    Args:
        product_name (str): 제품의 이름
        details (str): 제품의 주요 내용
        options (list): 광고 문구의 느낌을 담은 옵션들
    
    Returns:
        str: 생성된 광고 문구 또는 오류 메시지
    """
    url = "http://127.0.0.1:8000/create_ad"  # 광고 문구 생성 요청을 보낼 서버의 URL
    try:
        # POST 요청을 보내면서 제품명, 상세 내용, 광고 톤을 JSON 형식으로 전달
        response = requests.post(
            url,
            json={
                "product_name": product_name,
                "details": details,
                "tone_and_manner": ", ".join(options)  # 선택된 옵션들을 문자열로 병합
            }
        )
        # 서버 응답이 성공적일 경우
        if response.status_code == 200:
            data = response.json()  # JSON 형식으로 응답 데이터를 파싱
            ad = data["ad"]         # 응답에서 광고 문구를 추출
            return ad
        else:
            return "광고 문구 생성 실패!"  # 서버가 성공적으로 응답하지 못한 경우
    except:
        return "서버 연결 실패"  # 서버에 연결할 수 없는 경우

# Gradio 화면 구성 함수
def main():
    """
    Gradio를 사용해 사용자 인터페이스를 생성하는 함수입니다.
    """
    with gr.Blocks() as demo:  # Gradio Blocks 컨테이너를 생성
        gr.Markdown("광고 문구를 생성해주는 서비스 앱")  # 앱의 제목 및 설명
        
        # 사용자 입력 필드를 수평으로 배치
        with gr.Row():
            product_name = gr.Textbox(label="제품 이름", placeholder="제품 이름을 입력하세요")  # 제품 이름 입력창
            details = gr.Textbox(label="주요 내용", placeholder="제품의 주요 내용을 입력하세요")  # 제품 주요 내용 입력창
        
        # 광고 문구의 느낌을 선택할 수 있는 체크박스 그룹
        options = gr.CheckboxGroup(
            label="광고 문구의 느낌",
            choices=["기본", "재밌게", "차분하게", "과장스럽게", "참신하게", "고급스럽게", "센스있게", "가볍게"],
            value=["기본"]  # 기본 선택값 설정
        )
        
        # 문구 생성 버튼
        generate_button = gr.Button("문구 생성하기")  # 버튼 생성
        
        # 생성된 광고 문구를 표시할 출력창 (편집 불가능)
        ad_output = gr.Textbox(label="생성된 광고 문구", interactive=False)
        
        # 버튼 클릭 시 `generate_ad` 함수 호출
        generate_button.click(
            generate_ad,            # 호출할 함수
            inputs=[product_name, details, options],  # 입력값으로 사용할 요소들
            outputs=[ad_output]     # 출력값을 표시할 요소
        )
    
    return demo  # 생성된 Gradio 인터페이스 반환

# 실행
if __name__ == "__main__":
    app = main()       # Gradio 앱 생성
    app.launch()       # 로컬 서버에서 Gradio 앱 실행

 

2. main.py

import openai
from fastapi import FastAPI
from pydantic import BaseModel
from pymongo import MongoClient
openai.api_key="api_key키 입력"
url = "몽고DB 주소입력"
mongodb = MongoClient(url)
database = mongodb['kdt']
collection = database['gptad']
class AdGenerator:
    def __init__(self, engine='gpt-3.5-turbo'):
        self.engine = engine
    def using_chatgpt(self, prompt):
        system_instruction = "assistant는 마케팅 문구 작성 도우미로 동작한다. user의 내용을 참고하여 마케팅 문구를 작성해라."
        messages = [{"role":"system", "content":system_instruction},
                    {"role":"user", "content": prompt}]
        response = openai.chat.completions.create(model=self.engine, messages=messages)
        result = response.choices[0].message.content.strip()
        return result
    def generate_prompt(self, product_name, details, tone_and_manner):
        prompt = f'제품 이름: {product_name}\n주요 내용: {details}\n광고 문구의 스타일: {tone_and_manner}\n위 내용을 참고하여 마케팅 문구를 만들어라'
        result = self.using_chatgpt(prompt=prompt)
        return result
class Product(BaseModel):
    product_name: str
    details: str
    tone_and_manner: str
app = FastAPI()
@app.post("/create_ad")
async def create_ad(product: Product):
    ad_generator = AdGenerator()
    ad = ad_generator.generate_prompt(
        product_name=product.product_name,
        details=product.details,
        tone_and_manner=product.tone_and_manner
    )
    data_insert = {
        "product_name": product.product_name,
        "details": product.details,
        "tone_and_manner": product.tone_and_manner,
        "ad": ad
    }
    result = collection.insert_one(data_insert)
    print(result.inserted_id)
    return {"ad": ad}

-->

설명글 추가(참고)

import openai                    # OpenAI API를 사용하기 위한 라이브러리
from fastapi import FastAPI      # FastAPI 웹 프레임워크를 가져옴
from pydantic import BaseModel   # 데이터 검증 및 모델링을 위한 Pydantic 라이브러리
from pymongo import MongoClient  # MongoDB와 상호작용하기 위한 라이브러리

# OpenAI API 키 설정 (사용자의 API 키로 교체 필요)
openai.api_key = "api_key키 입력"

# MongoDB 클라이언트 연결 설정 (MongoDB 주소 입력 필요)
url = "몽고DB 주소입력"
mongodb = MongoClient(url)          # MongoDB 클라이언트 생성
database = mongodb['kdt']           # 'kdt'라는 이름의 데이터베이스 선택
collection = database['gptad']      # 'gptad'라는 이름의 컬렉션 선택

# 광고 생성 클래스 정의
class AdGenerator:
    def __init__(self, engine='gpt-3.5-turbo'):
        """
        AdGenerator 클래스의 생성자.
        
        Args:
            engine (str): 사용할 OpenAI 모델의 이름 (기본값은 'gpt-3.5-turbo')
        """
        self.engine = engine
    
    def using_chatgpt(self, prompt):
        """
        ChatGPT API를 사용해 마케팅 문구를 생성하는 메서드.
        
        Args:
            prompt (str): 사용자로부터 전달받은 프롬프트 문자열
        
        Returns:
            str: 생성된 마케팅 문구
        """
        # 시스템 메시지: AI가 마케팅 문구 도우미로 동작하도록 지시
        system_instruction = "assistant는 마케팅 문구 작성 도우미로 동작한다. user의 내용을 참고하여 마케팅 문구를 작성해라."
        
        # 메시지 리스트 생성 (시스템 메시지 + 사용자 메시지)
        messages = [
            {"role": "system", "content": system_instruction},
            {"role": "user", "content": prompt}
        ]
        
        # OpenAI API를 호출하여 응답 받기
        response = openai.chat.completions.create(model=self.engine, messages=messages)
        
        # 응답에서 생성된 문구를 추출하고 앞뒤 공백을 제거
        result = response.choices[0].message.content.strip()
        return result
    
    def generate_prompt(self, product_name, details, tone_and_manner):
        """
        사용자 입력을 기반으로 프롬프트를 생성하고 마케팅 문구를 생성하는 메서드.
        
        Args:
            product_name (str): 제품 이름
            details (str): 제품의 주요 내용
            tone_and_manner (str): 광고 문구의 스타일 (톤과 느낌)
        
        Returns:
            str: 생성된 마케팅 문구
        """
        # 프롬프트 텍스트 생성
        prompt = (
            f'제품 이름: {product_name}\n'
            f'주요 내용: {details}\n'
            f'광고 문구의 스타일: {tone_and_manner}\n'
            f'위 내용을 참고하여 마케팅 문구를 만들어라'
        )
        
        # ChatGPT를 사용해 프롬프트로부터 광고 문구 생성
        result = self.using_chatgpt(prompt=prompt)
        return result

# FastAPI의 데이터 모델 정의 (입력값의 스키마를 지정)
class Product(BaseModel):
    product_name: str      # 제품 이름
    details: str           # 제품의 주요 내용
    tone_and_manner: str   # 광고 문구의 스타일 (톤과 느낌)

# FastAPI 앱 생성
app = FastAPI()

# 광고 문구 생성 API 엔드포인트
@app.post("/create_ad")
async def create_ad(product: Product):
    """
    광고 문구를 생성하는 POST 요청 핸들러.
    
    Args:
        product (Product): 제품 이름, 주요 내용, 광고 스타일이 담긴 요청 데이터
        
    Returns:
        dict: 생성된 광고 문구를 담은 딕셔너리
    """
    # AdGenerator 클래스의 인스턴스 생성
    ad_generator = AdGenerator()
    
    # 광고 문구 생성
    ad = ad_generator.generate_prompt(
        product_name=product.product_name,
        details=product.details,
        tone_and_manner=product.tone_and_manner
    )
    
    # MongoDB에 데이터 삽입
    data_insert = {
        "product_name": product.product_name,
        "details": product.details,
        "tone_and_manner": product.tone_and_manner,
        "ad": ad
    }
    result = collection.insert_one(data_insert)  # 데이터베이스에 문서 삽입
    print(result.inserted_id)                    # 삽입된 문서의 ID 출력
    
    # 생성된 광고 문구를 반환
    return {"ad": ad}
728x90
LIST

'LLM(Large Language Model)의 기초' 카테고리의 다른 글

1. 판다스(Pandas)  (2) 2024.12.17
넘파이(Numpy)  (0) 2024.12.16
Gradio  (3) 2024.12.11
프롬프트 엔지니어링  (8) 2024.12.11
몽고 DB 와 파이썬  (6) 2024.12.10