- π 2025 POSTECH Digital Twin Chatbot Hackathon β 1st Place (Grand Prize, 25.09.28.) ![Demo μμ λ§ν¬]
Deepcatch Agentλ ν¬ν κ΅¬λ£‘ν¬ λμ κ΄κ΄κ°μ μν΄ μ€κ³λ AI κΈ°λ° μ ν μμ½ μ΄μμ€ν΄νΈμ λλ€. LangGraphλ‘ κ΅¬μ±λ μμ΄μ νΈκ° κΈ°μ/μ΄ν λ°μ΄ν°λ₯Ό μμ§ν΄ λ§μΆ€ νλμ μ μνκ³ , Twilio μμ± ν΅νλ₯Ό ν΅ν΄ λμμ μμ½κΉμ§ λμ΅λλ€. Next.js λμ보λμμλ λν νμ€ν 리, μ€μκ° μ μ¬, λΆμ μΈμ¬μ΄νΈλ₯Ό νλμ νμΈν μ μμ΅λλ€.
- Deepcatch Agent
- λͺ©ν: μ¬μ©μμ λμ μΌμ μꡬμ¬νμ μ΄ν΄νκ³ , κΈ°μ/μ΄ν μ 보λ₯Ό λ°νμΌλ‘ λ§μΆ€ νλμ μ μνλ©°, νμ μ μ ν μμ½μ λνν©λλ€.
- ꡬμ±:
- LangGraph μμ΄μ νΈ: λν, νλλ, μ ν λ Έλλ‘ κ΅¬μ±λ λ©ν°ν΄ νμ΄νλΌμΈ
- FastAPI λ°±μλ: μμ°λ¬Ό/κΈ°μ API λν, Twilio μΉν , LangGraph μ€ν, SQLite μν κ΄λ¦¬
- Next.js νλ°νΈμλ: μ€μκ° μ μ¬, λꡬ κ²°κ³Ό, μΆμ² νλμ μκ°ννλ λμ보λ
- Socket.IO λΈλ¦¬μ§: OpenAI Realtime λ° Twilio λ―Έλμ΄ μ΄λ²€νΈλ₯Ό ν΅ν©
deepcatch-agent/
βββ front-end/ # Next.js 15 + Tailwind λμ보λ
β βββ src/
β β βββ app/ # App Router νμ΄μ§ λ° API λΌμ°νΈ
β β βββ components/ # λμ보λ, UI, μ°¨νΈ μ»΄ν¬λνΈ
β β βββ ai/flows/ # Genkit κΈ°λ° μμ½ νλ‘μ°
β β βββ lib/ # μ€μ , μ€μκ° μμΌ ν΄λΌμ΄μΈνΈ λ±
β βββ package.json
β βββ README.md
βββ server/ # FastAPI + LangGraph + Twilio λ°±μλ
β βββ src/ # API, μμ΄μ νΈ, μλΉμ€ λ μ΄μ΄
β βββ app/ # (λ κ±°μ) Flask μ€νμ© μ½λ
β βββ data/ # μν DB/CSV
β βββ pyproject.toml
β βββ README.md
βββ data/ # SQLite DB (μ€νμ©)
βββ README.md # β μ§κΈ λ³΄κ³ μλ νμΌ
- λνν μΌμ μμ§: LangGraph νλλκ° λ μ§, μΈμ, μμ° λ± ν΅μ¬ μ¬λ‘―μ μ§μ·보κ΄
- κΈ°μ/λ¬Όλ μΈμ¬μ΄νΈ: κ΅¬λ£‘ν¬ μΆμ μ°ν΄(10/5~10/8) λ§μΆ€ μ보, νμ/νκ³ μ°¨νΈ, μΆμ² μΌμ μ 곡
- μ΄ν λ°μ΄ν° λΆμ: μ΅κ·Ό μ΄νλ μΆμΈ, μ£Όμ μ΄μ’ μ°¨νΈ, μ ν μ λ° μ 보
- μ€μκ° ν΅ν μ€νΈλ¦¬λ°: Socket.IOλ₯Ό ν΅ν Twilio/OpenAI μμ± μ΄λ²€νΈ μ ν, λμ보λ μ μ¬ λ λλ§
- μ ν μμ½ μλν: Twilio APIλ‘ μ€μ μ ν λ°μ λ° κ²°κ³Ό μμ½
- λ§΅ κ²½λ‘ μκ°ν: Kakao μ§λ κΈ°λ° μΆμ² λμμ κ²½λ‘/μμΉ νμ
μ¬μ©μ β Next.js λμ보λ β FastAPI (LangGraph) β μΈλΆ API (κΈ°μμ², DPG)
β Twilio β μμ± ν΅ν
Socket.IO λΈλ¦¬μ§ β OpenAI Realtime β μ€μκ° μ μ¬/μλ΅ μ€νΈλ¦¬λ°
- λν νλ¦: νλ°νΈ β
/chatβ LangGraph β Weather/Fish Tool νΈμΆ β μλ΅/λꡬ λ©νλ°μ΄ν° β λμ보λ μΉ΄λ λ°μ - ν΅ν νλ¦: νλ°νΈ β Socket.IO
start_callβ OpenAI/Twilio μ°κ²° β μ€μκ° μ΄λ²€νΈ βRealtimeTranscriptionμ»΄ν¬λνΈ μ λ°μ΄νΈ
| νλͺ© | λ²μ | λΉκ³ |
|---|---|---|
| Node.js | β₯ 18 | Next.js 15 λμ (npm λλ pnpm μ¬μ© κ°λ₯) |
| Python | 3.10β3.11 | uv κΆμ₯ |
| uv | μ΅μ | λ°±μλ μ’ μμ±/λͺ λ Ή μ€ν |
| SQLite | κΈ°λ³Έ λ΄μ₯ | ν
μ€νΈ λ°μ΄ν° data/fishing.db ν¬ν¨ |
| ngrok (μ ν) | μ΅μ | Twilio μΉν λ‘컬 μ°λμ© |
| Twilio κ³μ (μ ν) | - | μ€μ μ ν λ°μ μ νμ |
git clone https://github.com/sjin4861/deepcatch-agent.git
cd deepcatch-agentcd server
uv sync # μμ‘΄μ± μ€μΉ (pyproject.toml κΈ°λ°)
cp .env.example .env # νμ μ νκ²½ λ³μ μμ
uv run uvicorn src.main:app --reload --port 8000- κΈ°λ³Έμ μΌλ‘
http://localhost:8000μμ API μ 곡 USE_SSL=trueμ€μ νpython run_https.pyλ‘ HTTPS μ€ν κ°λ₯- LangGraph/Socket.IO μλ²λ FastAPI μ±μ ν¬ν¨λμ΄ μμ΅λλ€.
cd front-end
npm install # pnpm / yarn μ¬μ© κ°λ₯
npm run dev # http://localhost:9002 (package.jsonμ dev μ€ν¬λ¦½νΈ)νμ μ λ€μ νκ²½ λ³μ(.env.local) μ€μ :
NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
NEXT_PUBLIC_SOCKET_URL=http://localhost:8000
NEXT_PUBLIC_KAKAO_MAP_KEY=μΉ΄μΉ΄μ€_μ§λ_Javascript_ν€- FastAPI μ±μ΄ Socket.IO ASGI μλ²(
/socket.io)λ₯Ό ν¨κ» μ 곡νλ―λ‘ μΆκ° μ€ν μμ΄ μλ - OpenAI Realtimeμ μ¬μ©ν κ²½μ°
.envμOPENAI_API_KEYλ₯Ό μΆκ°νκ³ λΈλΌμ°μ μμ ν΅νλ₯Ό μμνμΈμ.
# Twilio (μ ν)
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_NUMBER=
# DPG μ λ°/μ΄ν API
DPG_SERVICE_KEY=...
FISHERY_API_DEV_MODE=true # trueλ©΄ mock λ°μ΄ν° μ¬μ©
# κΈ°μμ² API
WEATHER_AUTH_KEY=...
WEATHER_URL=https://apihub.kma.go.kr/api/typ01/url/fct_shrt_reg.php
WEATHER_CODE_URL=...
# OpenAI Realtime
OPENAI_API_KEY=sk-...
# κΈ°ν
USE_SSL=falseNEXT_PUBLIC_API_BASE_URL=http://localhost:8000
NEXT_PUBLIC_SOCKET_URL=http://localhost:8000
NEXT_PUBLIC_KAKAO_MAP_KEY=...-
λν νλ‘μ°
- μ¬μ©μκ° νλ°νΈ λνμ°½μμ λ¬Έμ β FastAPI
/chat - LangGraph
FishingPlannerGraphκ° λꡬ νΈμΆ/μλ΅ κ²°μ - Weather/Fish Tool κ²°κ³Όλ
toolResultsλ‘ νλ°νΈμ μ€νΈλ¦¬λ°λμ΄ μΈν¬ μΉ΄λ λ° μ°¨νΈμ λ°μ
- μ¬μ©μκ° νλ°νΈ λνμ°½μμ λ¬Έμ β FastAPI
-
κΈ°μ λ°μ΄ν° νμ΄νλΌμΈ
/api/v1/ship-safe/holiday/forecastμμ μΆμ μ°ν΄ 4μΌμΉ νμ/νκ³ /λ¬Όλ μ 곡- WeatherToolμ΄ Holiday Forecastλ₯Ό λ³ν©ν΄ μ΅μ μΌμ , μ°¨νΈ λ©νλ°μ΄ν° μμ±
HolidayWeatherWidgetμμ μ°¨νΈ λ° νμ΄λΌμ΄νΈ λ λλ§
-
μ€μκ° ν΅ν
RealtimeTranscriptionμ»΄ν¬λνΈκ° Socket.IO μ΄λ²€νΈ(call_status,transcription_update,ai_response_*) μμ- ν΅ν μν/κ²½κ³Ό μκ°μ μ¦μ μ λ°μ΄νΈ, μ€νΈλ¦¬λ° ν μ€νΈλ₯Ό νμ ν¨κ³Όλ‘ νν
- Twilio webhook(
/voice/status) β μλ² β Socket.IOcall_status_update
| μμ | λͺ λ Ή | λΉκ³ |
|---|---|---|
| λ°±μλ Lint/Test | uv run pytest |
app/tests/test_api.py λ± |
| λ°±μλ νμ κ²μ¬ | uv run python -m compileall src |
λΉ λ₯Έ λ¬Έλ² μ²΄ν¬ |
| νλ°νΈμλ Lint | npm run lint |
ESLint + Next.js μ€μ |
| νλ°νΈμλ νμ μ²΄ν¬ | npm run typecheck |
TypeScript --noEmit |
- ν΅ν μνκ° κ°±μ λμ§ μμ λ: νλ°νΈ
.env.localμNEXT_PUBLIC_SOCKET_URLμ΄ FastAPI νΈμ€νΈμ μΌμΉνλμ§ νμΈνμΈμ. - κΈ°μ/μ΄ν API μλ¬:
FISHERY_API_DEV_MODE=trueμνμμ mock λ°μ΄ν°κ° μ 곡λ©λλ€. μ€μ API μΈμ¦ν€κ° μ ν¨νμ§ μ κ²νμΈμ. - Kakao μ§λ λ―Ένμ: λΈλΌμ°μ μ½μμ
appkeyμλ¬λ₯Ό νμΈνκ³NEXT_PUBLIC_KAKAO_MAP_KEYλ₯Ό μ¬νμΈνμΈμ. - OpenAI Realtime μ°κ²° μ€ν¨:
OPENAI_API_KEYμ λ€νΈμν¬ κΆν(λ°©νλ²½ λ±)μ νμΈν©λλ€.
λ³Έ νλ‘μ νΈλ LICENSEμ λͺ
μλ 쑰건μ λ°λ¦
λλ€. λ΄λΆ λ°μ΄ν°(data/ νμ SQLite/CSV)λ λ°λͺ¨ λͺ©μ μ μμμ΄λ©°, μ€μ μλΉμ€ λ°°ν¬ μ κ΅μ²΄κ° νμν©λλ€.