ποΈ RAG κΈ°λ° AI λͺ¨μλ©΄μ
μ€μκ° μμ± λ©΄μ Β· RAG λ§μΆ€ μ§λ¬Έ Β· AI νΌλλ°± 리ν¬νΈλ₯Ό μ 곡νλ μΉ μ ν리μΌμ΄μ
νλ‘μ νΈ μκ°
μ·¨μ
μ€λΉμμ΄ μ€μ κ³Ό λμΌν νκ²½μμ AI λ©΄μ κ΄κ³Ό 1:1 μμ± λ©΄μ μ μ°μ΅ν μ μλ μλΉμ€μ
λλ€.
μ΄λ ₯μΒ·μμμλ₯Ό κΈ°λ°μΌλ‘ μ§λ¬΄μ κΌ λ§λ μ§λ¬Έμ μ€μκ°μΌλ‘ μμ±νκ³ , λ©΄μ μ’
λ£ ν LLMμ΄ λ΅λ³μ λΆμν΄ μ’
ν© νΌλλ°± 리ν¬νΈλ₯Ό μ 곡ν©λλ€.
μ£Όμ κΈ°λ₯
π JWT μΈμ¦
μ΄λ©μΌ/λΉλ°λ²νΈ λ‘κ·ΈμΈ ν JWT ν ν°μ λ°κΈλ°μ λͺ¨λ API μμ²μ μλμΌλ‘ 첨λΆν©λλ€.
μ± μ¬μ μ μ μ μ₯λ ν ν°μΌλ‘ μΈμ
μ μλ 볡μν©λλ€.
π 4λ¨κ³ μμ λ μΈμ μ€μ
λ©΄μ μμ μ λ¨κ³λ³ κ°μ΄λλ₯Ό ν΅ν΄ μ€μ μ μλ£ν©λλ€.
| λ¨κ³ | λ΄μ© |
|---|---|
| 1 | μ΄λ ₯μ / μμμ μ λ‘λ λ° μ ν |
| 2 | μ§μ μ§λ¬΄ Β· λ©΄μ μκ° μ€μ |
| 3 | λ§μ΄ν¬ μ€λμ€ λ 벨 ν μ€νΈ |
| 4 | μ 체 μ€μ μμ½ νμΈ ν λ©΄μ μμ |
ποΈ μ€μκ° μμ± λ©΄μ
LiveKit WebRTC κΈ°λ° μμ± μ°κ²°λ‘ μ€μ λ©΄μ κ³Ό λμΌν νκ²½μ μ 곡ν©λλ€.
- μ 체 λ©΄μ νμ΄λ¨Έ β μ€μ λ μκ° μΉ΄μ΄νΈλ€μ΄
- λ΅λ³ νμ΄λ¨Έ β μ§λ¬ΈλΉ μ΅λ 90μ΄, 10μ΄ μ κ²½κ³ μλ¦Ό
- λ§μ΄ν¬ μ μ΄ β ON/OFF ν κΈ
- μ€μκ° μ΄λ²€νΈ λ‘κ·Έ β λ©΄μ μ§ν μν© κΈ°λ‘
π AI νΌλλ°± 리ν¬νΈ
λ©΄μ μ’ λ£ ν LLMμ΄ λ΅λ³ μ 체λ₯Ό λΆμν΄ λ¦¬ν¬νΈλ₯Ό μλ μμ±ν©λλ€.
| μ§ν | μ€λͺ |
|---|---|
| κΈ°μ μ νμ± | κΈ°μ κ°λ μ μ¬λ°λ₯Έ μ΄ν΄ λ° μ€λͺ μμ€ |
| λ Όλ¦¬μ± | λ΅λ³μ ꡬ쑰μ κ·Όκ±° μ κ° λ°©μ |
| κΉμ΄ | μ£Όμ μ λν μ¬ν μ΄ν΄λ |
| μ λ¬λ ₯ | λͺ ννκ³ κ°κ²°ν μμ¬μ λ¬ λ₯λ ₯ |
μ’ ν© μ μμ ν¨κ» μ§λ¬Έλ³ λ΄ λ΅λ³ vs λͺ¨λ² λ΅μ λΉκ΅λ₯Ό μ 곡ν©λλ€.
π λμ λ©΄μ κΈ°λ‘
κ³Όκ±° λ©΄μ μΈμ μ λͺ©λ‘ λ° μμΈ κΈ°λ‘(μ μ, νΌλλ°±, μ§λ¬Έ/λ΅λ³)μ μ‘°νν μ μμ΅λλ€.
π₯ ν¬μΈμΏ ν€
λ©΄μ μ κΈ΄μ₯μ νμ΄μ£Όλ μμν μ¬λ―Έ μμμ
λλ€.
μΏ ν€λ₯Ό ν΄λ¦νλ©΄ 20κ°μ§ μμ λ©μμ§ μ€ νλκ° λλ€μΌλ‘ λ±μ₯ν©λλ€.
νλ©΄ νλ¦
ν νλ©΄
β
βββ λ‘κ·ΈμΈ
β
βββ λ©΄μ μμ
β
βΌ
μΈμ
μ€μ μμ λ
Step 1 Β· Step 2 Β· Step 3 Β· Step 4
β
βΌ
μ€μκ° λ©΄μ μ§ν
(μμ± μ°κ²° Β· νμ΄λ¨Έ Β· μ§λ¬Έ νμ)
β
βΌ
AI νκ° μ€...
β
βΌ
νΌλλ°± 리ν¬νΈ
(μ μ Β· μ§ν Β· λͺ¨λ² λ΅μ)
β
βΌ
λ©΄μ κΈ°λ‘ μ μ₯ β κΈ°λ‘ μ‘°ν
κΈ°μ μ€ν
| λΆλ₯ | κΈ°μ |
|---|---|
| UI νλ μμν¬ | React 18 |
| λΌμ°ν | React Router DOM v7 |
| λΉλ λꡬ | Vite 5 |
| μ€μκ° μμ± | LiveKit Client (WebRTC) |
| μ€νμΌ | 컀μ€ν CSS (CSS Variables λμμΈ μμ€ν ) |
| μΈμ¦ | JWT (localStorage) |
| ν μ€νΈ | Vitest |
νλ‘μ νΈ κ΅¬μ‘°
src/
βββ api/
β βββ authApi.js # λ‘κ·ΈμΈ, λ΄ μ 보 μ‘°ν
β βββ interviewApi.js # μΈμ
μμ± / μ’
λ£ / κ²°κ³Ό μ‘°ν
β βββ interviewHistoryApi.js # κΈ°λ‘ μ μ₯ / λͺ©λ‘ / μμΈ
βββ auth/
β βββ tokenStorage.js # JWT ν ν° κ΄λ¦¬
βββ components/
β βββ HomeView.jsx # ν (νμ΄λ‘ Β· νΌμ² μΉ΄λ Β· ν¬μΈμΏ ν€)
β βββ LoginForm.jsx # λ‘κ·ΈμΈ
β βββ SessionSetupForm.jsx # 4λ¨κ³ μμ λ μΈμ
μ€μ
β βββ InterviewRoom.jsx # μ€μκ° λ©΄μ
β βββ EvaluatingView.jsx # AI νκ° λκΈ°
β βββ ResultView.jsx # νΌλλ°± 리ν¬νΈ
β βββ HistoryListView.jsx # λ©΄μ κΈ°λ‘ λͺ©λ‘
β βββ HistoryDetailView.jsx # λ©΄μ κΈ°λ‘ μμΈ
β βββ FortuneCookie.jsx # ν¬μΈμΏ ν€
βββ hooks/
β βββ useCountdown.js # μΉ΄μ΄νΈλ€μ΄ νμ΄λ¨Έ ν
βββ App.jsx # λΌμ°ν
Β· μ μ μν
βββ styles.css # μ μ λμμΈ μμ€ν
λ°±μλ μ°λ ꡬ쑰
[νλ‘ νΈμλ] [λ°±μλ μλ²]
β β
βββ POST /v1/auth/login βββββββββΆ JWT λ°κΈ
βββ GET /v1/auth/me ββββββββββββΆ μΈμ
νμΈ
β β
βββ POST /v1/interviews/sessions βΆ λ©΄μ μΈμ
μμ±
β βββΆ LiveKit ν ν° λ°ν
β β
βββ POST /sessions/{id}/end βββββΆ λ©΄μ μ’
λ£ β AI νκ° μμ
β β
βββ GET /sessions/{id}/result ββΆ κ²°κ³Ό ν΄λ§ (4μ΄ κ°κ²©)
β EVALUATING β λκΈ° βββΆ μλ£ μ 리ν¬νΈ λ°ν
β β
βββ POST /v1/interviews/results βΆ κ²°κ³Ό κΈ°λ‘ μ μ₯
GET /v1/interviews/results ββΆ λ΄ κΈ°λ‘ λͺ©λ‘
GET /v1/interviews/results/{id} βΆ κΈ°λ‘ μμΈ
λ©΄μ μΈμ μμ± μμ²
POST /v1/interviews/sessions
{
"resumeIds": 1,
"coverLetter": 3,
"jobField": "BACKEND",
"durationMinutes": 15
}
μ§μ μ§λ¬΄: BACKEND Β· FRONTEND Β· ANDROID Β· IOS Β· DEVOPS Β· DATA Β· AI
νΌλλ°± 리ν¬νΈ μλ΅
{
"score": 85,
"overallFeedback": "κΈ°μ μ΄ν΄λκ° λκ³ λ
Όλ¦¬μ μΈ λ΅λ³μ ꡬμ±νμ΅λλ€...",
"qaList": [
{
"turn": 1,
"question": "μ΅κ·Ό νλ‘μ νΈμμ μ΄λ €μ λ κΈ°μ μμ¬κ²°μ μ μ€λͺ
ν΄μ£ΌμΈμ.",
"userAnswer": "μ λ ...",
"bestAnswer": "μ΄μμ μΈ λ΅λ³μ ..."
}
]
}
μμνκΈ°
# μμ‘΄μ± μ€μΉ
npm install
# νκ²½ λ³μ μ€μ
cp .env.example .env
# .env νμΌμμ λ°±μλ μλ² μ£Όμ μ
λ ₯
# κ°λ° μλ² μ€ν
npm run dev
νκ²½ λ³μ
VITE_BACKEND_BASE_URL=http://localhost:8080
VITE_API_BASE_URL=http://localhost:8080/v1/interviews
VITE_AUTH_BASE_URL=http://localhost:8080/v1/auth
λ°±μλ μ°λ λ¬Έμ
API λͺ
μΈ μ λ¬Έμ docs/backend-integration-spec.mdλ₯Ό μ°Έκ³ νμΈμ.