MBTI ๊ธฐ๋ฐ T/F ์๋ก ๋ฐฉ์ ๋ถ๋ฅ ๊ฒ์ โ FastAPI + KoBERT + Hugging Face
- Base URL:
http://localhost:8000 - API ๋ฒ์ : v1
- ์ธ์ฝ๋ฉ: UTF-8
์๋ก์ด ๊ฒ์ ์ธ์ ์ ์์ํฉ๋๋ค.
- URL:
POST /api/v1/game/start - ์์ฒญ ๋ณธ๋ฌธ:
{ "nickname": "์ฌ์ฉ์๋๋ค์", "user_type": "T" // "T" ๋๋ "F" ์ค ํ๋ } - ์ฑ๊ณต ์๋ต (200):
{ "session_id": "์์ฑ๋_์ธ์ _ID", "message": "Game started successfully" } - ์๋ฌ ์๋ต:
- 400: ์๋ชป๋ ์์ฒญ (์: ์๋ชป๋ user_type)
- 500: ์๋ฒ ๋ด๋ถ ์ค๋ฅ
ํน์ ๋ผ์ด๋์ ์ํฉ๊ณผ ์์ ์๋ต์ ์กฐํํฉ๋๋ค.
- URL:
GET /api/v1/game/round/{session_id}/{round_number} - ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ:
session_id: ๊ฒ์ ์ธ์ IDround_number: ๋ผ์ด๋ ๋ฒํธ (1-5)
- ์ฑ๊ณต ์๋ต (200):
{ "round_number": 1, "situation": "์ฐ์ธ_๊ฐ๋ฑ", "scenario": "๋น์ ์ ์ฐ์ธ์ด ๋น์ ์ ๊ณํ์ ๋ฌด์ํ๊ณ ๋ค๋ฅธ ์ฝ์์ ์ก์์ ๋ ์ด๋ป๊ฒ ๋ฐ์ํ์๊ฒ ์ต๋๊น?", "example_response": "๊ด์ฐฎ์, ๋ค์์ ๊ฐ์ด ํ์." } - ์๋ฌ ์๋ต:
- 400: ์๋ชป๋ ์์ฒญ
- 404: ํด๋น ๋ผ์ด๋ ๋๋ ์ธ์ ์ ์ฐพ์ ์ ์์
์ฌ์ฉ์์ ์๋ต์ ์ ์ถํ๊ณ ์ ์๋ฅผ ํ์ธํฉ๋๋ค.
- URL:
POST /api/v1/game/submit - ์์ฒญ ๋ณธ๋ฌธ:
{ "session_id": "์ธ์ _ID", "user_response": "์ฌ์ฉ์ ์๋ต ํ ์คํธ", "round_number": 1, "situation": "์ฐ์ธ_๊ฐ๋ฑ" } - ์ฑ๊ณต ์๋ต (200):
{ "round_number": 1, "score": 85, "feedback": "์ข์ ๋ฐ์์ด์์!", "is_completed": true } - ์๋ฌ ์๋ต:
- 400: ์๋ชป๋ ์์ฒญ
- 404: ์ธ์ ์ ์ฐพ์ ์ ์๊ฑฐ๋ ์ด๋ฏธ ์๋ฃ๋ ๋ผ์ด๋
๊ฒ์ ๊ฒฐ๊ณผ์ ๋ฆฌ๋๋ณด๋ ์์๋ฅผ ํ์ธํฉ๋๋ค.
- URL:
GET /api/v1/game/summary/{session_id} - ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ:
session_id: ๊ฒ์ ์ธ์ ID
- ์ฑ๊ณต ์๋ต (200):
{ "session_id": "์ธ์ _ID", "nickname": "์ฌ์ฉ์๋๋ค์", "total_score": 420, "round_scores": [85, 90, 80, 85, 80], "rank": 3, "total_players": 150 } - ์๋ฌ ์๋ต:
- 400: ์๋ชป๋ ์์ฒญ
- 404: ์ธ์ ์ ์ฐพ์ ์ ์๊ฑฐ๋ ๊ฒ์์ด ์์ง ์๋ฃ๋์ง ์์
๋ค์ ๋๋ฉ์ธ์์์ ์์ฒญ์ด ํ์ฉ๋ฉ๋๋ค:
- http://localhost
- http://localhost:3000
- http://127.0.0.1
- http://127.0.0.1:3000
- https://your-production-domain.com
๋ชจ๋ API๋ ํ์ค HTTP ์ํ ์ฝ๋๋ฅผ ์ฌ์ฉํฉ๋๋ค:
- 200: ์ฑ๊ณต
- 400: ์๋ชป๋ ์์ฒญ
- 404: ๋ฆฌ์์ค๋ฅผ ์ฐพ์ ์ ์์
- 500: ์๋ฒ ๋ด๋ถ ์ค๋ฅ
์๋ฌ ์๋ต ์์:
{
"detail": "์๋ฌ ๋ฉ์์ง"
}- ๋ชจ๋ ์์ฒญ์ JSON ํ์์ด์ด์ผ ํฉ๋๋ค.
- ์ธ์ฆ์ด ํ์ํ ๊ฒฝ์ฐ, ์ถํ API ํค ๋๋ JWT ํ ํฐ์ด ํ์ํ ์ ์์ต๋๋ค.
- ์ค์ ๋ฐฐํฌ ์์๋ HTTPS๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
All error responses follow this format:
{
"detail": "Error message here"
}400 Bad Request: Invalid request data401 Unauthorized: Missing or invalid authentication403 Forbidden: Insufficient permissions404 Not Found: Resource not found422 Unprocessable Entity: Validation error500 Internal Server Error: Server error
-
Install PostgreSQL if you haven't already:
- Mac:
brew install postgresql - Ubuntu:
sudo apt-get install postgresql postgresql-contrib - Windows: Download from PostgreSQL Downloads
- Mac:
-
Create a new database and user:
# Connect to PostgreSQL psql postgres # Create a new database CREATE DATABASE mbti_game; # Create a new user (replace 'password' with a secure password) CREATE USER mbti_user WITH PASSWORD 'password'; # Grant privileges GRANT ALL PRIVILEGES ON DATABASE mbti_game TO mbti_user; # Exit psql \q
-
Set up environment variables:
cp .env.example .env
Then edit the
.envfile with your database credentials.
# ๊ฐ์ํ๊ฒฝ ์์ฑ (macOS/Linux)
python3 -m venv venv
source venv/bin/activate # Windows: .\venv\Scripts\activate
# ์์กด์ฑ ์ค์น
pip3 install -r requirements.txt# ๊ฐ๋ฐ ๋ชจ๋๋ก ์คํ (์๋ ๋ฆฌ๋ก๋ ํ์ฑํ)
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 --log-level debugcurl -X POST http://127.0.0.1:8000/game/start \
-H "Content-Type: application/json" \
-d '{"nickname":"ํ
์คํธ์ ์ ", "user_type":"T"}'- ๊ฐ ์ธ์ ๋ง๋ค 5๊ฐ์ ์ค๋ณต ์๋ ๋๋ค ์๋๋ฆฌ์ค๊ฐ ์ ๊ณต๋ฉ๋๋ค.
- ๋ฐ๋์ ๊ฒ์ ์์ ํ ๋ฐ์
session_id์ ๋ผ์ด๋ ๋ฒํธ(1~5)๋ฅผ ํจ๊ป ์์ฒญํด์ผ ํฉ๋๋ค.
# 1๋ผ์ด๋ ์ ๋ณด ์กฐํ ์์ (์ธ์
์์ฑ ํ)
curl http://127.0.0.1:8000/api/v1/game/round/{session_id}/1{session_id}๋ ๊ฒ์ ์์ ์ ์๋ต๋ฐ์ ๊ฐ์ ์ฌ์ฉํ์ธ์.- ์๋ต ์์:
{
"round_number": 1,
"situation": "์น๊ตฌ๊ฐ ์ํ์ ๋จ์ด์ก์ ๋",
"friend_message": "์ํ์ ๋จ์ด์ก์ด... ๋๋ฌด ์์ํด",
"example_response": ""
}- ๋ฐ๋์ ๊ฒ์ ์์ ์ ๋ฐ์ session_id์ round_number๋ฅผ ์ฌ์ฉํ์ธ์.
- ํ ๋ผ์ด๋์ ํ ๋ฒ๋ง ์๋ต์ด ํ์ฉ๋ฉ๋๋ค.
curl -X POST http://127.0.0.1:8000/api/v1/game/submit \
-H "Content-Type: application/json" \
-d '{"session_id":"์ธ์
_ID", "user_response":"๊ด์ฐฎ์? ๋ค์์๋ ๋ ์ํ ์ ์์ ๊ฑฐ์ผ!", "round_number":1}'# ์ธ์
ID๋ก ๊ฒฐ๊ณผ ์กฐํ
curl http://127.0.0.1:8000/api/v1/game/summary/์ธ์
_IDcurl -X POST http://127.0.0.1:8000/api/v1/predict \
-H "Content-Type: application/json" \
-d '{"text": "๊ฐ์ ์น๊ตฌํํ
์๊ธฐํด๋ด."}'# ์ ๋ ํ
์คํธ ์คํ
pytest
# ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ํ์ธ (pytest-cov ์ค์น ํ์)
pytest --cov=app tests/**'๋T์ผ?'**๋ MBTI์ T(Thinking)ํ๊ณผ F(Feeling)ํ์ ์๋ก ์คํ์ผ ์ฐจ์ด๋ฅผ AI๊ฐ ํ์ตํ๊ณ , ์ฌ์ฉ์์ ๋ฌธ์ฅ์ ํ๊ฐํ์ฌ ์ ์ํํ๋ ์ธํฐ๋ํฐ๋ธ ๊ฒ์์
๋๋ค.
์ฌ์ฉ์๋ ์์ ๊ณผ ๋ฐ๋ ์ฑํฅ์ ์๋ก ๋ฐฉ์์ผ๋ก ๋ฌธ์ฅ์ ์์ฑํ๊ณ , AI๋ KoBERT ๊ธฐ๋ฐ ๋ถ๋ฅ ๋ชจ๋ธ๋ก ํด๋น ๋ฌธ์ฅ์ 'T/F์ค๋ฌ์'์ ์์นํํด ํผ๋๋ฐฑํฉ๋๋ค.
- ์ฌ์ฉ์ ์ ๋ ฅ ๋ฌธ์ฅ์ ๊ธฐ๋ฐ์ผ๋ก T/F ์ ์ฌ๋ ์์ธก
- ์ ์ํ ๋ฐ ๋์ ์ ์ ๊ด๋ฆฌ
- ๋ผ์ด๋๋ณ ์ํฉ ์ ๊ณต ๋ฐ ๋ถ์ ๊ฒฐ๊ณผ ๋ฆฌํด
- ์ ์ ์์ ๋ฐ ๋ฐฑ๋ถ์ ํต๊ณ ์ ๊ณต
- ๋ชจ๋ธ์ด ๋ก๋๋์ง ์์ ๊ฒฝ์ฐ
model_cache๋๋ ํ ๋ฆฌ๋ฅผ ์ญ์ ํ๊ณ ์ฌ์๋ํ์ธ์:rm -rf model_cache
token_type_ids๊ด๋ จ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์๋ฒ๋ฅผ ์ฌ์์ํ์ธ์.
- ์๋ฒ ๋ก๊ทธ๋ ํฐ๋ฏธ๋์ ์ค์๊ฐ์ผ๋ก ์ถ๋ ฅ๋ฉ๋๋ค.
--log-level debug์ต์ ์ผ๋ก ์์ธํ ๋ก๊ทธ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
POST /api/v1/game/start
์์ฒญ ๋ณธ๋ฌธ (JSON):
{
"nickname": "์ฌ์ฉ์๋๋ค์",
"user_type": "T" // ๋๋ "F"
}์ฑ๊ณต ์๋ต (200):
{
"session_id": "์์ฑ๋_์ธ์
_ID",
"message": "Game started successfully"
}GET /api/v1/game/round/{round_number}
๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ:
round_number: ๋ผ์ด๋ ๋ฒํธ (1-5)
์ฑ๊ณต ์๋ต (200):
{
"round_number": 1,
"situation": "์น๊ตฌ๊ฐ ์ํ์ ๋จ์ด์ก์ ๋",
"example_response": "๋๋ฌด ์์ํ๊ฒ ๋ค. ๊ด์ฐฎ์? ๊ธฐ๋ถ์ด ์ด๋?"
}POST /api/v1/game/score
์์ฒญ ๋ณธ๋ฌธ (JSON):
{
"session_id": "์ธ์
_ID",
"user_response": "์ฌ์ฉ์_์๋ต_ํ
์คํธ",
"round_number": 1
}์ฑ๊ณต ์๋ต (200):
{
"score": 78.5,
"message": "Response scored successfully"
}GET /api/v1/game/summary/{session_id}
๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ:
session_id: ๊ฒ์ ์ธ์ ID
์ฑ๊ณต ์๋ต (200):
{
"session_id": "์ธ์
_ID",
"nickname": "์ฌ์ฉ์๋๋ค์",
"user_type": "T",
"total_score": 350.5,
"round_scores": [
{
"round_number": 1,
"score": 78.5,
"user_response": "์ฌ์ฉ์_์๋ต_ํ
์คํธ",
"is_correct_style": true
}
],
"percentile": 85.5,
"rank": 4,
"top_players": [
{
"nickname": "์ต๊ณ ์",
"user_type": "F",
"total_score": 480,
"timestamp": "2025-06-14T12:00:00"
},
{
"nickname": "์ค๊ฐ์",
"user_type": "T",
"total_score": 420,
"timestamp": "2025-06-14T11:30:00"
},
{
"nickname": "์ด๋ณด์",
"user_type": "F",
"total_score": 380,
"timestamp": "2025-06-14T10:45:00"
}
],
"feedback": "ํ๋ฅญํด์! ๊ฐ์ ํ(F) ์คํ์ผ์ ๋งค์ฐ ์ ์ดํดํ๊ณ ๊ณ์๋ค์!"
}- ์ฌ์ฉ์๊ฐ ๋๋ค์๊ณผ ๋ณธ์ธ์ MBTI ์ ํ(T/F)์ ์ ๋ ฅํ์ฌ ๊ฒ์์ ์์ํฉ๋๋ค.
- ๊ฐ ๋ผ์ด๋๋ง๋ค ํน์ ์ํฉ์ด ์ ์๋ฉ๋๋ค.
- ์ฌ์ฉ์๋ ์ ์๋ ์ํฉ์ ๋ํด ๋ฐ๋ ์ฑํฅ์ ์คํ์ผ๋ก ์๋ต์ ์์ฑํฉ๋๋ค.
- T ์ ํ ์ฌ์ฉ์: F ์คํ์ผ๋ก ๊ฐ์ ์ ํํํ๋ ์๋ต ์์ฑ
- F ์ ํ ์ฌ์ฉ์: T ์คํ์ผ๋ก ๋ ผ๋ฆฌ์ ์ธ ์๋ต ์์ฑ
- AI ๋ชจ๋ธ์ด ์๋ต์ ๋ถ์ํ์ฌ ์ ์๋ฅผ ๋งค๊ธฐ๊ณ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.
- 5๋ผ์ด๋๊ฐ ์ข ๋ฃ๋๋ฉด ์ด์ , ์์, ๋ฐฑ๋ถ์, ์์ ํ๋ ์ด์ด ์ ๋ณด ๋ฑ์ ํฌํจํ ์ข ํฉ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
์ปค๋ฐ ๋ฉ์์ง๋ "๊ธฐ๋ฅ: ๊ธฐ๋ฅ์ค๋ช " ํ์์ผ๋ก ์์ฑํฉ๋๋ค.
| ์ ํ | ์ค๋ช |
|---|---|
feat |
์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ ๋๋ ๊ธฐ์กด ๊ธฐ๋ฅ ์์ |
fix |
๊ธฐ๋ฅ์ ๋ํ ๋ฒ๊ทธ ์์ |
build |
๋น๋ ๊ด๋ จ ์์ |
chore |
ํจํค์ง ๋งค๋์ ์์ ๋ฐ ๊ธฐํ ์์ (์: .gitignore) |
docs |
๋ฌธ์(์ฃผ์) ์์ |
style |
์ฝ๋ ์คํ์ผ ๋ฐ ํฌ๋งทํ ์์ (๊ธฐ๋ฅ ๋ณ๊ฒฝ ์์) |
refactor |
๊ธฐ๋ฅ ๋ณ๊ฒฝ ์์ด ์ฝ๋ ๋ฆฌํฉํฐ๋ง (์: ๋ณ์๋ช ๋ณ๊ฒฝ) |
feat: Add user authentication
fix: Resolve login button bug