📘 Aura_AI Day 13
GPT 연동 + 모달 상태 저장 + 프론트/백엔드 연결 고도화 (A ~ Z 완전 정리)
안녕하세요.
Aura AI 프로젝트 13일차 기록입니다.
오늘은 단순히 “GPT 붙이기”가 아니라,
채팅 입력 → 모달 선택값 포함 → FastAPI → GPT 호출 → 응답 반환 → UI 표시
이 전체 파이프라인을 처음부터 끝까지 완성한 날입니다.
즉,
👉 프론트 상태관리 + 백엔드 API + GPT 서비스 + 보안 + UX까지 모두 연결한 날이라고 보시면 됩니다.
이 글 하나만 보셔도,
- 왜 이런 구조로 설계했는지
- 각 파일이 왜 필요한지
- 코드가 어떻게 연결되는지
- 실무에서는 왜 이런 패턴을 쓰는지
처음 보는 분도 이해하실 수 있도록 A부터 Z까지 전부 설명드리겠습니다.
✅ 0️⃣ 오늘 목표 한 줄 요약
“채팅을 보내면 GPT가 실제로 답변하는 완전한 서비스 구조 만들기”
기존:
- UI만 존재 (더미 응답)
오늘:
- 실제 GPT API 호출
- 모달 선택값까지 함께 전달
- 백엔드 통해 응답 반환
즉, 가짜 챗봇 → 진짜 AI 서비스로 전환했습니다.
✅ 1️⃣ 오늘 변경된 파일 목록
📌 추가
gpt_service.py
backend/.gitignore
📌 수정
main.py
chats.py
chat.py
ChatContainer.tsx
ChatHeader.tsx
DateModal.tsx
LocationModal.tsx
StyleModal.tsx
chatContextStore.ts
.env.local
backend/.env
✅ 2️⃣ 환경 변수 & 보안 설정 (매우 중요 ⭐)
GPT 프로젝트에서 가장 위험한 부분 = API Key 노출입니다.
키가 깃허브에 올라가면?
👉 몇 분 만에 수십만 원 비용 폭탄 맞을 수 있습니다.
그래서 환경 변수 + .gitignore는 필수입니다.
🔹 프론트 (.env.local)
NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
왜 필요한가요?
❌ 나쁜 방식
fetch("http://localhost:8000/chats/start")
- 배포 시 주소 전부 수정해야 함
- 유지보수 최악
✅ 좋은 방식
process.env.NEXT_PUBLIC_API_BASE_URL
- 개발/운영 환경 분리 가능
- 배포 시 주소만 교체
- 실무 표준 방식
🔹 백엔드 (backend/.env)
OPENAI_API_KEY=sk-xxxx
왜 필요한가요?
- GPT 키 코드 하드코딩 ❌
- 보안 취약
- 깃허브 업로드 위험
그래서
backend/.gitignore
.env
추가 → 깃 추적 차단
✅ 3️⃣ 백엔드 구조 설계
여기부터가 오늘의 핵심입니다.
오늘 가장 중요하게 잡은 원칙:
Router ≠ 비즈니스 로직
👉 로직은 Service 레이어로 분리
왜냐하면 실무에서는 반드시 이렇게 합니다.
🔹 backend/main.py
추가 이유
.env 읽기 위해 load_dotenv() 필요
load_dotenv()
왜?
- 민감정보 외부 관리
- 코드 보안 강화
- 배포 환경 전환 쉬움
🔹 schemas/chat.py
class ChatRequest(BaseModel):
message: str
context: str | None = None
왜 context를 추가했을까요?
오늘 핵심 기능 때문입니다.
우리는:
- 날짜
- 위치
- 성별
- 스타일
이 정보들을 GPT에게 같이 보내야 합니다.
예시:
날짜: 12월 25일
위치: 서울
성별: 여자
스타일: 데이트룩
이 정보가 있어야 GPT가 더 똑똑한 추천을 합니다.
즉,
단순 챗봇 → 개인화 추천 AI
로 업그레이드되는 포인트입니다.
🔹 services/gpt_service.py ⭐ (오늘 핵심 파일)
왜 따로 분리했을까요?
많은 초보자들이 이렇게 합니다:
❌ Router 안에서 GPT 호출
@router.post("/start")
async def start():
openai 호출...
문제점:
- 코드 지저분
- 테스트 어려움
- 재사용 불가
- 유지보수 최악
✅ 실무 표준 방식
Router → Service → GPT
역할 분리:
- Router = 입구
- Service = 로직 처리
장점
✅ 테스트 쉬움
✅ 재사용 가능
✅ 코드 가독성 상승
✅ 유지보수 편함
✅ 실무 아키텍처 패턴
AsyncOpenAI 사용 이유
GPT 응답 = 느림 (1~3초)
동기 방식이면?
👉 서버 전체가 멈춤
그래서
async def ask_gpt()
비동기 필수
timeout 추가 이유
timeout=20
- GPT 무한 대기 방지
- 서버 안정성 확보
temperature=0.7 이유
- 0 → 너무 기계적
- 1 → 너무 랜덤
0.7 = 자연스러운 대화 톤
🔹 routers/chats.py
reply = await ask_gpt(body.message, body.context)
async로 바꾼 이유
Service가 async이기 때문입니다.
FastAPI는
async → async 체인 유지
가 성능상 가장 좋습니다.
✅ 4️⃣ 프론트엔드 상태 관리 설계
오늘 프론트 핵심은 이것입니다.
“모달 선택값을 어떻게 채팅과 연결할 것인가?”
🔹 Zustand 사용
useChatContextStore
왜 Redux가 아니라 Zustand?
이 프로젝트 규모에서는:
- Redux = 너무 무거움
- 설정 복잡
Zustand:
✅ 가볍다
✅ 코드 간단
✅ 러닝커브 낮음
✅ 실무에서 많이 사용
→ 스타트업/소형 프로젝트 최적
🔹 ChatContainer.tsx (GPT 연결 핵심)
오늘 가장 중요한 흐름:
1. 사용자 입력
2. 전역 상태 가져오기
3. context 문자열 생성
4. API 호출
5. 응답 표시
UX 개선 포인트 ⭐
"응답 작성 중..."
GPT는 느립니다.
그래서:
- 로딩 메시지 표시
- 사용자 체감 속도 개선
이 작은 디테일이 서비스 완성도를 크게 올립니다.
🔹 Modal들 (Date / Location / Style)
공통 철학:
“선택 → 전역 저장 → 어디서든 사용”
왜 전역 상태가 필요할까요?
만약:
DateModal → ChatContainer 직접 props 전달
이면?
👉 컴포넌트 깊어질수록 지옥
Zustand 사용 시
어디서든:
useChatContextStore()
즉시 접근 가능
장점
✅ props drilling 제거
✅ 코드 단순화
✅ 확장 쉬움
✅ 5️⃣ apiClient.ts
모든 API 호출을 한 곳에서 통일
왜 만들었을까요?
매번:
fetch()
try/catch
header
json 처리
복붙하면?
👉 유지보수 지옥
장점
✅ 에러 공통 처리
✅ 코드 중복 제거
✅ API 호출 통일
✅ 가독성 상승
✅ 6️⃣ 전체 연결 흐름 한 눈에 보기
모달 선택
↓
Zustand 저장
↓
ChatContainer context 생성
↓
apiFetch("/chats/start")
↓
FastAPI Router
↓
gpt_service.py
↓
OpenAI GPT
↓
응답 반환
↓
UI 업데이트
👉 완전한 End-to-End 파이프라인 완성
✅ 7️⃣ 오늘 아키텍처 선택 이유 정리 (핵심 요약 ⭐)
선택이유장점
| Service 분리 | 로직 분리 | 유지보수 쉬움 |
| Async | GPT 느림 대응 | 성능 향상 |
| Zustand | 가벼운 상태관리 | 단순/빠름 |
| .env | 보안 | 키 보호 |
| apiClient | 공통 처리 | 중복 제거 |
| Context 전달 | 개인화 추천 | UX 향상 |
✅ 🔥 오늘의 핵심 성과
오늘로 인해:
✅ 실제 GPT 연결 완료
✅ 개인화 컨텍스트 전달
✅ 전역 상태 관리 구축
✅ 보안 설정 완료
✅ 실무 구조 확립
✅ UX 개선
즉,
“데모 수준 → 실제 서비스 수준”
으로 단계가 올라간 날입니다.
'챗봇 공부 노트' 카테고리의 다른 글
| [15편] 채팅 요약 기능 구현 + UX 고도화 (1) | 2026.02.02 |
|---|---|
| [14편] 날씨 기반 GPT 추천/위치 검색 연동 및 JSON 응답 고도화 (0) | 2026.02.01 |
| [12편] 모달 선택값 전역 저장 및 채팅 context 연동 (0) | 2026.01.30 |
| [11편] API 구조 & 데이터 계약(Contract) 고정 (0) | 2026.01.26 |
| [10편] FastAPI 백엔드 분리 & 프론트엔드 연동 (1) | 2026.01.26 |