🇶 Streamlit을 사용해서 AI 모델을 웹 애플리케이션에 통합하려면 모델 로드, 사용자 입력, 결과 출력의 단계를 거쳐야합니다. 각각의 단계에 대해 설명해주세요.
1. 모델 로드
- 학습이 완료된 AI 모델 파일(예: .pth, .h5, .pkl 등)이나 Hugging Face 등의 API를 통해 모델을 메모리에 올리는 단계이다.
- @st.cache_resource 데코레이터를 사용하여 모델을 메모리에 딱 한 번만 로드하고, 이후 재실행될 때는 캐싱된 모델 객체를 그대로 재사용한다.
2. 사용자 입력
- 사용자가 AI 모델에게 예측을 요청할 데이터(텍스트, 이미지, 수치 등)를 웹 화면을 통해 입력받는 단계이다.
- 주요 위젯 예시:
- 텍스트 (LLM, 챗봇, 감성 분석): st.text_input(), st.text_area()
- 이미지 (컴퓨터 비전, 객체 탐지): st.file_uploader(type=['png', 'jpg'])
- 수치/카테고리 (정형 데이터 예측): st.slider(), st.selectbox(), st.number_input()
3. 결과 출력
- 사용자가 입력한 데이터를 AI 모델에 전달하여 추론을 수행하고, 그 결과를 사용자가 이해하기 쉬운 시각적 형태로 화면에 보여주는 단계이다.
- AI 모델의 연산은 시간이 걸릴 수 있으므로, 실행 중임을 알리는 로딩 스피너를 보여주는 것이 좋다.
- 주요 출력 위젯:
- 상태 표시: st.spinner() (로딩 중 표시), st.success() (성공 메시지)
- 텍스트 및 결과: st.write(), st.json()
- 시각화: st.image() (분석된 이미지 출력), st.plotly_chart() 또는 st.line_chart() (예측 확률 그래프)
🇶 FastAPI를 활용하여 AI 모델을 통합한 웹 API를 구현할 때, 기능별로 나눠서 구성하는 것이 바람직합니다. 전체적인 API 서버 코드 구조는 어떻게 구성되면 좋을지 자유롭게 작성해보세요.
my_ai_api_project/
│
│── app/
│ │── __init__.py
│ │── main.py # FastAPI 앱 초기화 및 엔드포인트 라우터 등록
│ │
│ │── core/ # 앱 전체 공통 설정 및 보안
│ │ │── config.py # 환경 변수 및 설정 (Pydantic Settings)
│ │ └── security.py # API 키 검증 등 보안 관련
│ │
│ │── api/ # 클라이언트 요청을 받는 라우터 계층
│ │ │── v1/
│ │ │ │── endpoints/
│ │ │ │ │── predict.py # AI 추론 요청 API (Predict, Classify 등)
│ │ │ │ └── health.py # 서버 상태 점검 (Health Check)
│ │ │ └── api.py # v1 라우터 통합 파일
│ │
│ │── schemas/ # 요청/응답 데이터 검증 (Pydantic 모델)
│ │ │── predict_req.py # 추론 요청 스키마 (예: 이미지 파일, 텍스트)
│ │ └── predict_res.py # 추론 결과 응답 스키마 (예: 클래스명, 확률 값)
│ │
│ │── services/ # 비즈니스 로직 및 AI 전/후처리 계층
│ │ └── ai_inference.py # 데이터 전처리 -> 모델 추론 -> 후처리 파이프라인
│ │
│ └── models/ # AI 모델 정의 및 로더 계층
│ │── model_loader.py # 싱글톤 패턴 기반의 AI 모델 로드 (메모리 관리)
│ └── weights/ # (선택) 로컬 모델 가중치 파일 저장소 (.pth, .onnx 등)
│
│── tests/ # 유닛 테스트 및 API 통합 테스트
│ └── test_predict.py
│
│── .env # 환경 변수 파일 (모델 경로, API 키 등)
│── Dockerfile # 컨테이너화를 위한 도커 파일
│── requirements.txt # 의존성 패키지 목록
└── README.md
1. app/main.py (진입점)
FastAPI 인스턴스를 생성하고 Global Middleware, Exception Handler, 그리고 API 라우터를 연결한다.
2. app/models/model_loader.py (모델 관리)
수백 MB에서 수 GB에 달하는 AI 모델 객체를 안전하게 관리하는 계층이다.
3. app/schemas/ (데이터 검증)
Pydantic을 사용하여 클라이언트가 보낸 입력 데이터 포맷이 맞는지 검증하고, AI가 뱉은 정제되지 않은 출력을 깔끔한 JSON 형태로 포맷팅하여 응답한다.
4. app/services/ai_inference.py (비즈니스 로직)
컨트롤러(Router)와 모델 사이에서 가장 핵심적인 연산 파이프라인을 담당한다.
5. app/api/v1/endpoints/predict.py (라우터)
클라이언트의 HTTP 요청을 직접 받아 매핑해주는 창구이다.
🇶 현존하는 AI 웹/앱서비스를 하나 선정하세요. (가상의 서비스로 해보는 것도 좋아요.) 그 서비스가 지금까지 학습한 Docker, 추론 최적화, Streamlit, FastAPI로 구현되었다고 가정하고, 전체 아키텍처를 작성해보세요. 만약 가능하다면, 보안 요소(CORS 등)/멀티유저 요청 처리 방안(비동기 처리, 대기 큐 등)/클라우드 배포 구조(GCP, AWS)/모니터링 및 로깅 전략 까지 포함하여 작성해보세요.
<AI 기반 알약 식별 및 복약 안내 서비스>
1. 전체 서비스 아키텍처 개요
전체 시스템은 클라이언트 측의 Frontend(Streamlit)와 비즈니스 로직 및 AI 추론을 담당하는 Backend(FastAPI)로 분리된 MSA(Microservice Architecture) 형태를 띈다. 멀티유저의 무거운 추론 요청을 버티기 위해 비동기 작업 큐(Celery + Redis)를 도입하고, 모든 컴포넌트는 Docker 컨테이너로 추상화되어 Cloud 환경에 배포된다.
2. 컴포넌트별 구현 및 통합 방안
① Frontend: Streamlit
- 역할: 사용자가 알약 이미지를 업로드(st.file_uploader)하고 결과를 확인할 수 있는 가벼운 웹 대시보드 인터페이스를 제공한다.
- 통합 방식: Streamlit 자체에서 AI 모델을 무겁게 로드하지 않고, 사용자가 이미지를 제출하면 FastAPI 백엔드의 엔드포인트로 REST API(Post) 요청을 보낸다.
- UX 처리: 비동기 요청 후 응답을 기다리는 동안 st.spinner()를 활용해 로딩 상태를 보여주며, 백엔드로부터 완료 신호를 받으면 화면을 리렌더링하여 알약 정보 테이블을 출력한다.
② Backend: FastAPI
- 역할: 클라이언트의 요청 접수, 데이터 검증(Pydantic), 인증, 작업 스케줄링 및 최종 결과 반환을 담당한다.
- 통합 방식: lifespan 이벤트를 통해 서버 시작 시 라우팅 규칙 및 보안 설정을 초기화한다. 무거운 이미지 추론 요청이 들어오면 백엔드가 직접 계산하지 않고, Celery 작업 큐에 태스크를 발행(Task Enqueue)한 뒤 즉시 작업 ID(Task ID)를 클라이언트에 반환(202 Accepted)하여 엔드포인트가 블로킹되는 것을 방지한다.
③ 추론 엔진: 최적화된 AI 모델 (YOLO / CNN)
- 모델 최적화: Edge 및 클라우드 인프라 비용 절감과 지연 시간 단축을 위해, 학습된 PyTorch API 가중치 모델을 TensorRT 또는 ONNX Runtime 포맷으로 변환(Quantization: FP32 ➔ FP16/INT8)하여 추론 속도를 최대 3~5배 최적화한다.
- 서빙 인프라: Celery Worker 내부에서 최적화된 ONNX Runtime Engine을 싱글톤 패턴으로 로드하여 사용한다.
④ 가상화: Docker
- 다중 컨테이너 구성: streamlit-app, fastapi-api, celery-worker, redis-broker 총 4개의 레이어로 이미지를 독립 분리한다.
- 최적화 및 보안: * AI 모델 서빙 환경의 용량을 줄이기 위해 python:3.10-slim 빌드 베이스를 사용하고, 멀티 스테이지 빌드를 적용한다.
- GPU 가속이 필요한 celery-worker 컨테이너에는 nvidia/cuda 베이스 이미지를 적용하고 Docker Runtime에 --gpus all 옵션을 부여한다.
3. 고도화 요구사항 반영
① 보안 요소 (Security & CORS)
- CORS (Cross-Origin Resource Sharing) 설정: Streamlit 프론트엔드 도메인과 FastAPI 백엔드 도메인이 다를 경우 발생하는 웹 보안 문제를 방지하기 위해, FastAPI 내부에 CORSMiddleware를 설정하여 허용된 프론트엔드 출처(Origin)만 접근 가능하도록 제한한다.
- API Rate Limiting & Auth: 악의적인 DDoS 공격이나 무차별적인 API 호출로 인한 GPU 자원 고갈을 막기 위해, slowapi 라이브러리를 활용해 IP당 분당 호출 횟수(예: 60회)를 제한하고, 헤더에 JWT 또는 API Token 검증 레이어를 둔다.
② 멀티유저 요청 처리 (Async & Queue)
- 비동기 아키텍처: 다수의 사용자가 동시에 수십 메가바이트의 알약 이미지를 업로드할 때 백엔드가 멈추는 현상을 막기 위해 Celery(Worker) + Redis(Message Broker) 구조를 채택한다.
- 처리 흐름:
- User ➔ FastAPI: 알약 이미지 업로드.
- FastAPI ➔ Redis: 이미지를 S3에 임시 저장 후, S3 URL을 담은 추론 태스크를 Redis 큐에 적재. FastAPI는 유저에게 {"task_id": "abc-123"}와 함께 202 Accepted 응답을 즉시 반환.
- Celery Worker ➔ GPU: 백그라운드에서 대기 중이던 Celery 워커가 큐에서 작업을 하나씩 가져와 GPU 자원을 할당받고 ONNX 모델 추론을 수행.
- 결과 저장 및 폴링: 완료된 분석 결과(알약명, 성분 등)는 Redis Result Backend에 저장되며, Streamlit 프론트엔드는 task_id를 이용해 백엔드의 상태 조회 엔드포인트를 주기적으로 확인(Polling)하거나 WebSocket을 통해 결과를 전달받아 화면에 출력.
③ 클라우드 배포 구조 (AWS 및 GCP 가이드)
- AWS 가상 시나리오:
- Frontend / Backend API: AWS ECS (Fargate)를 통해 서버리스 컨테이너 형태로 배포하여 트래픽에 따라 컨테이너 개수가 자동 조절되도록 설정한다. 앞단에는 Application Load Balancer (ALB)를 배치한다.
- Celery Worker (Inference): GPU 인스턴스가 필요하므로 g4dn.xlarge 등 GPU 아키텍처를 지원하는 AWS Amazon EC2 인스턴스 그룹 또는 ECS (EC2 Launch Type)로 구성하여 관리한다.
- Storage & Cache: 정적 이미지 파일은 Amazon S3, 메시지 브로커는 Amazon ElastiCache for Redis를 연동한다.
- GCP 가상 시나리오:
- Cloud Run을 통해 FastAPI와 Streamlit을 서버리스로 서빙하고, GPU 연산이 필요한 워커 노드는 GKE(Google Kubernetes Engine)의 GPU 노드 풀을 활용해 관리한다. 메시지 브로커로는 Cloud Memorystore for Redis를 채택한다.
④ 모니터링 및 로깅 전략
- 애플리케이션 메트릭 모니터링: FastAPI에 prometheus-fastapi-instrumentator를 연동하여 API 응답 지연 시간(Latency), HTTP 에러율(4xx/5xx), 처리량(RPS)을 수집하고 Prometheus가 이를 수집하여 Grafana 대시보드에 시각화한다.
- 중앙 집중형 로깅: 모든 Docker 컨테이너의 표준 출력(stdout) 로그는 Loki 또는 AWS CloudWatch Logs로 전송된다. 알약 이미지 전처리 오류, AI 예측 확률(Confidence Score) 저하 스코어 등을 구조화된 JSON 로그 포맷(structlog)으로 기록하여 추후 모델 재학습 데이터 선별에 활용한다.
- Celery 태스크 모니터링: Flower 대시보드를 컨테이너로 함께 띄워, 현재 큐에 쌓여 있는 대기 작업 수와 워커의 GPU 작업 처리 상태를 실시간으로 모니터링한다.