챗봇 공부 노트

[13편] GPT 연동 + 모달 상태 저장

frontend-diary-log 2026. 2. 1. 00:25

 

📘 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 개선


즉,

“데모 수준 → 실제 서비스 수준”

으로 단계가 올라간 날입니다.