Google Gemini 2.0 Flash ๊ธฐ๋ฐ ๋ง์ถคํ ์ฌํ ์ผ์ ์์ฑ AI ์๋ฒ
- ํ๋ก์ ํธ ๊ฐ์
- ์ฃผ์ ๊ธฐ๋ฅ
- ๊ธฐ์ ์คํ
- ์์คํ ์ํคํ ์ฒ
- ๋ฐ์ดํฐ ๋ชจ๋ธ
- API ๋ช ์ธ
- ์ค์น ๋ฐ ์คํ
- Spring Boot ์ฐ๋
TripTalk AI Server๋ ์ฌ์ฉ์์ ์ฌํ ์คํ์ผ, ๋ชฉ์ ์ง, ์์ฐ, ๋ํ์ธ ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Google Gemini 2.0 Flash API๋ฅผ ํ์ฉํ์ฌ ๋ง์ถคํ ์ฌํ ์ผ์ ์ ์๋ ์์ฑํ๋ FastAPI ๊ธฐ๋ฐ AI ์๋ฒ์ ๋๋ค.
์์ฑ๋ ์ฌํ ๊ณํ์ JSON ํ์ผ๋ก ์์ ์ ์ฅ๋๋ฉฐ, ์ฌ์ฉ์ ํ์ธ ํ Spring Boot ์๋ฒ๋ก ์ ์ก๋์ด MySQL DB์ ์๊ตฌ ์ ์ฅ๋ฉ๋๋ค.
- ๐ค AI ๋ง์ถค ์ถ์ฒ: Google Gemini 2.0 Flash ๊ธฐ๋ฐ ๊ฐ์ธํ๋ ์ฌํ ์ผ์ ์์ฑ
- ๐ ์์ธ ์ผ์ : ์ผ๋ณ/์๊ฐ๋๋ณ ๊ตฌ์ฒด์ ์ธ ์ฌํ ๊ณํ (์๋น, ๊ด๊ด์ง, ๊ตํตํธ ํฌํจ)
- ๐จ ๊ตํตํธ/์์ ์ ๋ณด: ์ถ๋ฐํธ, ๊ทํํธ, ์์ ์์ฝ ์ ๋ณด ์๋ ์์ฑ
- ๐ Spring Boot ์ฐ๋: RESTful API ํต์ ์ผ๋ก ์๋ฒฝํ ์์คํ ํตํฉ
-
Google Gemini 2.0 Flash API ์ฐ๋
- ์ฌ์ฉ์ ์ ๋ ฅ ๊ธฐ๋ฐ ํ๋กฌํํธ ์์ฑ
- ์์ฐ์ด ๊ธฐ๋ฐ ๊ตฌ์กฐํ๋ JSON ์๋ต
- 9๊ฐ์ง ์ฌํ ์คํ์ผ ๋ถ์ (์ฒดํยท์กํฐ๋นํฐ, ์์ฐ๊ณผ ํจ๊ป, ์ฌ์ ๋กญ๊ฒ ํ๋ง ๋ฑ)
-
์์ธ ์ผ์ ์์ฑ
- ์ผ๋ณ ์ค์ผ์ค (DailySchedule)
- ์๊ฐ๋๋ณ ์์ธ ๊ณํ (ScheduleItem)
- ์ค์ ์๋นยท๊ด๊ด์ง ์ด๋ฆ ํฌํจ
- ๊ตํตํธ ์ ๋ณด (ํญ๊ณต์ฌ๋ช , ์ถ๋ฐ/๋์ฐฉ ์๊ฐ, ๊ฐ๊ฒฉ)
- ์์ ์ ๋ณด (ํธํ ๋ช , ์ฃผ์, 1๋ฐ ๊ฐ๊ฒฉ)
-
ํ์ด๋ผ์ดํธ ์ถ์ถ
- ์ฌํ์ ์ฃผ์ ํฌ์ธํธ 3-5๊ฐ ์๋ ์์ฑ
- ๊ฐ ํ์ด๋ผ์ดํธ 100์ ์ด๋ด
-
JSON ํ์ผ ๊ธฐ๋ฐ ์ ์ฅ
data/travel_data.json์ ์๊ตฌ ์ ์ฅ- UUID ๊ธฐ๋ฐ ๊ณ ์ ID ์์ฑ
- ์ค๋ณต ๋ฐฉ์ง ๋ก์ง (๋์ผ ์กฐ๊ฑด ์ ์ ๋ฐ์ดํธ)
-
์ฌํ ๋ชฉ๋ก ์กฐํ
- ์ ์ฒด ์ฌํ ๋ชฉ๋ก ๋ฐํ
- ํน์ ์ฌํ ์์ธ ์กฐํ
-
HTTP POST ํต์
- FastAPI โ Spring Boot REST API ํธ์ถ
- JSON ๋ฐ์ดํฐ ์๋ ์ง๋ ฌํ (camelCase ๋ณํ)
- ์๋ฌ ํธ๋ค๋ง ๋ฐ ์ฌ์๋ ๋ก์ง
-
๋ฐ์ดํฐ ๋ณํ
- Pydantic ๋ชจ๋ธ โ JSON (by_alias=True)
- snake_case โ camelCase ์๋ ๋ณํ
- Spring Boot DTO ํ์์ ๋ง์ถ ๋ฐ์ดํฐ ๊ตฌ์กฐ
- Language: Python 3.11+
- Framework: FastAPI 0.115.5
- AI: Google Gemini 2.0 Flash API
- Data Validation: Pydantic 2.10.3
- HTTP Client: httpx 0.28.1
- CORS: FastAPI CORS Middleware
- File System: JSON ํ์ผ ๊ธฐ๋ฐ ๋ฐ์ดํฐ ์ ์ฅ
- Data Format: UTF-8 JSON (ensure_ascii=False)
- Google Gemini API: Gemini 2.0 Flash ๊ธฐ๋ฐ ์ฌํ ์ผ์ ์์ฑ
- Spring Boot API: ์ฌํ ๊ณํ DB ์ ์ฅ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Client โ โโโ> โ FastAPI โ โโโ> โ Google โ
โ (Mobile) โ โ (AI Server) โ โ Gemini 2.0 โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ
โโโโโโโ> Spring Boot API
โ (DB ์ ์ฅ)
โ
โโโโโโโ> data/travel_data.json
(์์ ์ ์ฅ)
1. ์ฌ์ฉ์ ์
๋ ฅ (๋ชฉ์ ์ง, ๊ธฐ๊ฐ, ์์ฐ, ๋ํ์ธ, ์ฌํ ์คํ์ผ)
โ
2. FastAPI โ Google Gemini 2.0 Flash API ์์ฒญ
โ
3. Gemini โ ๊ตฌ์กฐํ๋ ์ฌํ ๊ณํ JSON ์์ฑ
โ
4. FastAPI โ Pydantic ๋ชจ๋ธ ๊ฒ์ฆ ๋ฐ ์ ์ฅ (travel_data.json)
โ
5. ์ฌ์ฉ์ ํ์ธ ํ "์ ์ฅ" ๋ฒํผ ํด๋ฆญ
โ
6. FastAPI โ Spring Boot API ํธ์ถ (POST /api/trip-plan/from-fastapi)
โ
7. Spring Boot โ MySQL DB ์ ์ฅ
class TravelStyle(BaseModel):
category: str # "์ฒดํยท์กํฐ๋นํฐ", "์์ฐ๊ณผ ํจ๊ป", "์ฌ์ ๋กญ๊ฒ ํ๋ง" ๋ฑclass ScheduleItem(BaseModel):
order_index: int # ์์
time: str # "09:00"
title: str # "๊นํฌ๊ณตํญ ์ถ๋ฐ"
description: str # "์ง์์ด LJ313ํธ์ผ๋ก ์ ์ฃผ ์ถ๋ฐ"class DailySchedule(BaseModel):
day: int # 1, 2, 3...
date: str # "2025-12-13"
schedules: List[ScheduleItem] # ์์ธ ์ผ์ ๋ฆฌ์คํธclass TripTransportation(BaseModel):
origin: str # "๊นํฌ๊ณตํญ"
destination: str # "์ ์ฃผ๊ณตํญ"
name: str # "์ง์์ดLJ313"
price: int # 45000class TripAccommodation(BaseModel):
name: str # "์ ์ฃผ์ ํ์๋ ํธํ
"
address: str # "์ ์ฃผ ์๊ทํฌ์..."
pricePerNight: int # 200000class TripPlan(BaseModel):
title: str # "์ ์ฃผ๋ 2๋ฐ 3์ผ ์ฐ์ ์ฌํ"
destination: str # "์ ์ฃผ๋"
departure: str # "์์ธ"
startDate: str (alias='start_date') # "2025-12-13"
endDate: str (alias='end_date') # "2025-12-15"
companions: str # "์น๊ตฌ"
budget: str # "70๋ง์"
travelStyles: List[TravelStyle] # ์ฌํ ์คํ์ผ ๋ฆฌ์คํธ
highlights: List[TripHighlight] # ํ์ด๋ผ์ดํธ ๋ฆฌ์คํธ
fullPlan: str (alias='full_plan') # ์ ์ฒด ํ
์คํธ ๊ณํ
dailySchedules: List[DailySchedule] # ์ผ๋ณ ์ผ์
outboundTransportation: TripTransportation # ์ถ๋ฐ ๊ตํตํธ
returnTransportation: TripTransportation # ๊ทํ ๊ตํตํธ
accommodations: List[TripAccommodation] # ์์ ๋ฆฌ์คํธProduction: http://52.78.55.147:8000
Local Development: http://localhost:8000
POST /Travel-Plan
Content-Type: application/json
{
"companions": "์น๊ตฌ",
"departure": "์์ธ",
"destination": "์ ์ฃผ๋",
"start_date": "2025-12-13",
"end_date": "2025-12-15",
"style": ["์์ฐ๊ณผ ํจ๊ป", "์ฌ์ ๋กญ๊ฒ ํ๋ง"],
"budget": "50๋ง์~70๋ง์"
}์๋ต ์์:
{
"travel_id": "37488429-3759-4320-9603-a0db0277bd56",
"title": "์ ์ฃผ๋ 2๋ฐ 3์ผ ์ฐ์ ์ฌํ",
"destination": "์ ์ฃผ๋",
"departure": "์์ธ",
"start_date": "2025-12-13",
"end_date": "2025-12-15",
"companions": "์น๊ตฌ",
"budget": "70๋ง์",
"travel_styles": [
{"category": "์์ฐ๊ณผ ํจ๊ป"}
],
"highlights": [
{"content": "๊ฒจ์ธ ๋ฐ๋ค ๋ง๋ฝํ๋ฉฐ ์ฐ์ ์ค๋
์ดฌ์"},
{"content": "๋ฐ๋ปํ ์จ์ฒ์ผ๋ก ํผ๋ก ํ๊ธฐ"},
{"content": "์ ์ฃผ ํ๋ผ์ง ๋ง์ง ํ๋ฐฉ"}
],
"daily_schedules": [
{
"day": 1,
"date": "2025-12-13",
"schedules": [
{
"order_index": 1,
"time": "07:30",
"title": "๋นํ๊ธฐ ํ์น",
"description": "๊นํฌ๊ณตํญ์์ ์ง์์ด LJ313ํธ์ผ๋ก ์ ์ฃผ๋ก ์ถ๋ฐ"
}
]
}
],
"outbound_transportation": {
"origin": "๊นํฌ๊ณตํญ",
"destination": "์ ์ฃผ๊ณตํญ",
"name": "์ง์์ดLJ313",
"price": 45000
},
"return_transportation": {...},
"accommodations": [...]
}GET /travel-summariesGET /travel-summary/{travel_id}POST /save-plan/{travel_id}
Response:
{
"success": true,
"message": "์ฌํ ๊ณํ์ด Spring Boot ์๋ฒ์ ์ฑ๊ณต์ ์ผ๋ก ์ ์ฅ๋์์ต๋๋ค.",
"spring_response": {
"id": 123,
"title": "์ ์ฃผ๋ 2๋ฐ 3์ผ ์ฐ์ ์ฌํ",
...
},
"fastapi_travel_id": "37488429-3759-4320-9603-a0db0277bd56"
}ํ์ฌ AWS EC2 (52.78.55.147)์ Docker Compose๋ก ๋ฐฐํฌ ์ด์ ์ค์ ๋๋ค.
- FastAPI Server: http://52.78.55.147:8000
- Spring Boot Server: http://52.78.55.147:8080
# ์๋ฒ์์ ์คํ
cd /path/to/TripTalk
docker-compose up -d
# ๋ก๊ทธ ํ์ธ
docker-compose logs -f fastapi
# ์ฌ์์
docker-compose restart fastapi
# ์ค์ง
docker-compose down.env ํ์ผ:
# Google Gemini API Key
GOOGLE_API_KEY=your-google-gemini-api-key-here
# Spring Boot Server URL (๋ฐฐํฌ ํ๊ฒฝ)
SPRING_BOOT_URL=http://52.78.55.147:8080- Python 3.11 ์ด์
- Google Gemini API Key
# ๊ฐ์ํ๊ฒฝ ์์ฑ
python3 -m venv venv
# ํ์ฑํ (macOS/Linux)
source venv/bin/activatepip install -r requirements.txtrequirements.txt:
fastapi==0.115.5
uvicorn==0.34.0
pydantic==2.10.3
google-generativeai==0.8.3
httpx==0.28.1
python-dotenv==1.0.1.env ํ์ผ:
GOOGLE_API_KEY=your-api-key
SPRING_BOOT_URL=http://localhost:8080# ๊ฐ๋ฐ ๋ชจ๋
uvicorn AI_Chat:app --reload --host 0.0.0.0 --port 8000# ๋ฐฐํฌ ์๋ฒ ํ
์คํธ
curl http://52.78.55.147:8000/travel-summaries
# ๋ก์ปฌ ํ
์คํธ
curl http://localhost:8000/travel-summariesDocker Compose๋ก ์ด์ ์ค์ด๋ฉฐ, docker-compose.yml ์ค์ :
version: "3.9"
services:
fastapi:
build: .
container_name: fastapi-server
ports:
- "8000:8000"
restart: always
environment:
GOOGLE_API_KEY: ${GOOGLE_API_KEY}
SPRING_BOOT_URL: http://52.78.55.147:8080
volumes:
- ./data:/app/data
- ./outputs:/app/outputsFROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "AI_Chat:app", "--host", "0.0.0.0", "--port", "8000"]# ์๋ฒ ๋ฐฐํฌ (์ฒ์ ๋๋ ์ฝ๋ ๋ณ๊ฒฝ ์)
docker-compose up -d --build
# ์๋ฒ ์ฌ์์
docker-compose restart
# ๋ก๊ทธ ํ์ธ
docker-compose logs -f fastapi
# ์๋ฒ ์ค์ง
docker-compose down
# ์ปจํ
์ด๋ ์ํ ํ์ธ
docker-compose ps1. FastAPI์์ ์ฌํ ๊ณํ ์์ฑ โ travel_data.json ์ ์ฅ
2. ์ฌ์ฉ์ ํ์ธ ํ "์ ์ฅ" ๋ฒํผ ํด๋ฆญ
3. FastAPI โ Spring Boot API ํธ์ถ
POST http://52.78.55.147:8080/api/trip-plan/from-fastapi
4. Spring Boot โ MySQL DB ์ ์ฅ
5. ์ ์ฅ ๊ฒฐ๊ณผ ๋ฐํ
FastAPI (snake_case) โ Spring Boot (camelCase)
# TripPlan ๋ชจ๋ธ (FastAPI)
plan_data = plan_response.model_dump(by_alias=True)
# startDate, endDate, dailySchedules... (camelCase)
# Spring Boot๋ก ์ ์ก (๋ฐฐํฌ ํ๊ฒฝ)
async with httpx.AsyncClient() as client:
response = await client.post(
"http://52.78.55.147:8080/api/trip-plan/from-fastapi",
json=plan_data
)Spring Boot CreateFromFastAPIDTO:
public static class CreateFromFastAPIDTO {
private String startDate; // FastAPI์์ "startDate" ์ ์ก
private String endDate;
private String budget;
private List<DailyScheduleDTO> dailySchedules;
// ...
}โโโโโโโโโโโโโโโโโโโ
โ Client App โ
โ (Mobile/Web) โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ FastAPI Server โ โ Spring Boot API โ โ Google โ
โ (Docker) โโ>โ (AWS EC2) โ โ Gemini API โ
โ Port: 8000 โ โ 52.78.55.147 โ โโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโฌโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ travel_data.jsonโ โ MySQL (RDS) โ
โ (๋ก์ปฌ ์ ์ฅ) โ โ (์๊ตฌ ์ ์ฅ) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
TripTalk/
โโโ AI_Chat.py # ๋ฉ์ธ FastAPI ์ ํ๋ฆฌ์ผ์ด์
โโโ main.py # ์ ํ๋ฆฌ์ผ์ด์
์ํธ๋ฆฌ ํฌ์ธํธ
โโโ requirements.txt # Python ํจํค์ง ์์กด์ฑ
โโโ .env # ํ๊ฒฝ๋ณ์ (OpenAI API Key)
โโโ Dockerfile # Docker ์ด๋ฏธ์ง ๋น๋ ํ์ผ
โโโ docker-compose.yml # Docker Compose ์ค์
โโโ README.md # ํ๋ก์ ํธ ๋ฌธ์
โโโ data/
โ โโโ travel_data.json # ์ฌํ ๊ณํ JSON ์ ์ฅ์
โโโ outputs/
โโโ latest_plan.md # ์ต์ ์ฌํ ๊ณํ ๋งํฌ๋ค์ด
- JSON ํ์ผ:
start_date,end_date(snake_case) - Python ๋ชจ๋ธ:
startDate,endDate(camelCase) - Spring Boot ์ ์ก:
startDate,endDate(camelCase)
class TripPlan(BaseModel):
startDate: str = Field(..., alias='start_date')
endDate: str = Field(..., alias='end_date')- Gemini 2.0 Flash์ ์์ฐ์ด ๊ธฐ๋ฐ JSON ์์ฑ
- Pydantic ๋ชจ๋ธ๊ณผ ์ผ์นํ๋ ๊ตฌ์กฐํ๋ ์๋ต
- ํ์ฑ ์๋ฌ ์ต์ํ
- ๋์ผ ์กฐ๊ฑด (๋ชฉ์ ์ง, ๊ธฐ๊ฐ, ๋ํ์, ์์ฐ, ์คํ์ผ) ์ ๊ธฐ์กด ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ
- ๋ค๋ฅธ ์กฐ๊ฑด ์ ์ UUID ์์ฑ
- Spring Boot ํต์ ์คํจ ์ ์ฌ์๋
- Google Gemini API ํ์์์ ์ฒ๋ฆฌ
- JSON ํ์ฑ ์๋ฌ ๋ณต๊ตฌ
| ํ์ (Type) | ์ค๋ช (Description) |
|---|---|
| Feat | ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ๊ฒฝ์ฐ |
| Fix | ์๋ฌยท๋ฒ๊ทธ๋ฅผ ์์ ํ ๊ฒฝ์ฐ |
| Design | CSS ๋ฑ UI ๋์์ธ์ ๋ณ๊ฒฝํ ๊ฒฝ์ฐ |
| HOTFIX | ๊ธํ๊ฒ ์น๋ช ์ ์ธ ์๋ฌ๋ฅผ ์ฆ์ ์์ ํ ๊ฒฝ์ฐ |
| Style | ์ฝ๋ ํฌ๋งท ๋ณ๊ฒฝ, ์ธ๋ฏธ์ฝ๋ก ๋๋ฝ ๋ฑ ๋ก์ง ๋ณ๊ฒฝ ์๋ ์คํ์ผ ์์ |
| Refactor | ๊ธฐ๋ฅ ๋ณํ ์์ด ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ ๊ฒฝ์ฐ |
| Comment | ์ฃผ์ ์ถ๊ฐ ๋๋ ๋ณ๊ฒฝ |
| Docs | ๋ฌธ์๋ฅผ ์์ ํ ๊ฒฝ์ฐ (README ๋ฑ) |
| Test | ํ ์คํธ ์ฝ๋ ์ถ๊ฐยท๋ณ๊ฒฝยท๋ฆฌํฉํ ๋ง |
| Chore | ๊ธฐํ ๋ณ๊ฒฝ์ฌํญ (๋น๋, ํจํค์ง, ์ค์ ํ์ผ ์์ ๋ฑ) |
| Rename | ํ์ผยทํด๋๋ช ์ ์์ ํ๊ฑฐ๋ ์ฎ๊ธฐ๋ ๊ฒฝ์ฐ |
git commit -m "Feat: Google Gemini 2.0 Flash ์ฌํ ๊ณํ ์์ฑ API ์ถ๊ฐ"
git commit -m "Fix: Spring Boot ์ฐ๋ ์ camelCase ๋ณํ ์ค๋ฅ ์์ "
git commit -m "Docs: README ๋ฐ์ดํฐ ๋ชจ๋ธ ์น์
์ถ๊ฐ"- โ Google Gemini 2.0 Flash ๊ธฐ๋ฐ ์ฌํ ๊ณํ ์์ฑ
- โ Pydantic ๋ชจ๋ธ ๊ธฐ๋ฐ ๋ฐ์ดํฐ ๊ฒ์ฆ
- โ JSON ํ์ผ ๊ธฐ๋ฐ ์๊ตฌ ์ ์ฅ
- โ Spring Boot API ์ฐ๋ ์๋ฃ
- โ camelCase/snake_case ์๋ ๋ณํ
๐ค TripTalk AI Server - ๋น์ ๋ง์ ์๋ฒฝํ ์ฌํ์ AI๊ฐ ์ค๊ณํฉ๋๋ค!