549 lines
15 KiB
Markdown
549 lines
15 KiB
Markdown
# 對話練習 API
|
||
|
||
## 📋 概述
|
||
Drama Ling 的核心功能 - 情境對話練習系統,包含場景對話、AI分析、回覆輔助等功能。
|
||
|
||
## 🎭 核心功能
|
||
|
||
### 對話系統特色
|
||
- **情境化對話**: 真實場景模擬(餐廳、機場、購物等)
|
||
- **AI智能回應**: OpenAI GPT-4o-mini 驅動的自然對話
|
||
- **即時分析**: 語法、語義、流暢度多維度評分
|
||
- **學習輔助**: 智能提示和回覆建議
|
||
- **進度追蹤**: 對話目標和完成度監控
|
||
|
||
## 📌 API 端點
|
||
|
||
### 1. 開始對話練習
|
||
```http
|
||
POST /api/v1/dialogues/start
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"difficulty_override": "A2",
|
||
"target_vocabulary": ["reservation", "menu", "order"],
|
||
"practice_mode": "guided" // guided, free_form, challenge
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"dialogue_id": "DLG_20240907_001",
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"session_token": "session_eyJhbGciOiJIUzI1NiIs...",
|
||
"dialogue_config": {
|
||
"max_turns": 12,
|
||
"time_limit": 600, // seconds
|
||
"difficulty_level": "A2",
|
||
"practice_mode": "guided"
|
||
},
|
||
"scenario_context": {
|
||
"setting": "高級義大利餐廳內部,晚上8點",
|
||
"location": "Milano Restaurant, 市中心",
|
||
"your_role": "顧客",
|
||
"ai_role": "餐廳服務員",
|
||
"objective": "成功預約座位並完成點餐",
|
||
"background_info": "這是一家需要預約的高檔餐廳,服務正式"
|
||
},
|
||
"initial_state": {
|
||
"life_points_cost": 1,
|
||
"remaining_life_points": 4,
|
||
"objectives": [
|
||
"確認預約",
|
||
"選擇餐桌",
|
||
"點餐主菜",
|
||
"完成付款"
|
||
]
|
||
},
|
||
"ai_opening": {
|
||
"message": "Good evening! Welcome to Milano Restaurant. Do you have a reservation with us tonight?",
|
||
"audio_url": "https://cdn.dramaling.com/audio/dialogues/DLG_20240907_001_001.mp3",
|
||
"audio_duration": 4.2,
|
||
"emotion": "polite_welcoming",
|
||
"formality_level": "formal",
|
||
"suggestions": [
|
||
"Yes, I have a reservation under Chen.",
|
||
"No, but could we get a table for two?",
|
||
"I'd like to check if you have any available tables."
|
||
]
|
||
}
|
||
},
|
||
"message": "Dialogue session started successfully"
|
||
}
|
||
```
|
||
|
||
#### 場景類型
|
||
- `SC_Restaurant_*`: 餐廳相關場景
|
||
- `SC_Airport_*`: 機場/旅行場景
|
||
- `SC_Shopping_*`: 購物場景
|
||
- `SC_Business_*`: 商務場景
|
||
- `SC_Medical_*`: 醫療場景
|
||
- `SC_Education_*`: 教育場景
|
||
|
||
### 2. 發送對話訊息
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/message
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"message": "Yes, I have a reservation under Chen for 8 PM for two people.",
|
||
"message_type": "text",
|
||
"audio_data": {
|
||
"audio_url": "https://cdn.dramaling.com/user_audio/msg001.mp3",
|
||
"duration": 3.5
|
||
},
|
||
"metadata": {
|
||
"input_method": "voice", // voice, keyboard
|
||
"confidence_level": 4, // 1-5, user's confidence
|
||
"time_taken": 15.2 // seconds to compose
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"turn_id": "TURN_002",
|
||
"dialogue_status": "active",
|
||
"ai_response": {
|
||
"message": "Excellent! Mr. Chen, party of two at 8 PM. Your table is ready. Would you prefer a window seat or would you like to sit in our main dining area?",
|
||
"audio_url": "https://cdn.dramaling.com/audio/dialogues/DLG_20240907_001_002.mp3",
|
||
"audio_duration": 6.8,
|
||
"emotion": "friendly_professional",
|
||
"formality_level": "formal",
|
||
"context_hints": {
|
||
"next_expected": "table_preference",
|
||
"vocabulary_focus": ["window seat", "dining area", "prefer"]
|
||
}
|
||
},
|
||
"user_analysis": {
|
||
"grammar_score": 90,
|
||
"semantic_score": 95,
|
||
"fluency_score": 85,
|
||
"pronunciation_score": 88,
|
||
"overall_score": 90,
|
||
"detailed_feedback": {
|
||
"strengths": [
|
||
"Perfect use of formal language",
|
||
"Appropriate information included",
|
||
"Natural sentence structure"
|
||
],
|
||
"improvements": [
|
||
"Consider adding 'please' for extra politeness"
|
||
],
|
||
"vocabulary_analysis": [
|
||
{
|
||
"word": "reservation",
|
||
"usage": "perfect",
|
||
"level": "A2",
|
||
"context_appropriateness": 5
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"dialogue_progress": {
|
||
"turns_completed": 2,
|
||
"estimated_turns_remaining": 6,
|
||
"progress_percentage": 25,
|
||
"objectives_status": {
|
||
"confirmed_reservation": true,
|
||
"selected_table": false,
|
||
"ordered_food": false,
|
||
"completed_payment": false
|
||
},
|
||
"current_phase": "table_selection"
|
||
},
|
||
"suggestions": [
|
||
"I'd love a window seat if available.",
|
||
"The main dining area sounds great.",
|
||
"Could we see both options first?"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 請求回覆輔助
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/assistance
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"assistance_type": "reply_guidance",
|
||
"context": {
|
||
"partner_message": "Would you prefer a window seat or would you like to sit in our main dining area?",
|
||
"scenario_context": "choosing table at restaurant",
|
||
"user_language_level": "A2",
|
||
"stuck_reason": "vocabulary", // vocabulary, grammar, context
|
||
"partial_response": "I would like..." // user's partial input
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"assistance_id": "AST_20240907_001",
|
||
"assistance_type": "reply_guidance",
|
||
"guidance": {
|
||
"intent_analysis": "對方在詢問你的座位偏好,這是餐廳服務的常見情況",
|
||
"response_strategy": "表達你的偏好並保持禮貌",
|
||
"key_phrases": [
|
||
{
|
||
"phrase": "I'd prefer...",
|
||
"meaning": "我比較喜歡...",
|
||
"usage": "表達偏好的禮貌方式"
|
||
},
|
||
{
|
||
"phrase": "window seat",
|
||
"meaning": "靠窗座位",
|
||
"usage": "餐廳座位類型"
|
||
}
|
||
],
|
||
"sample_responses": [
|
||
{
|
||
"response": "I'd prefer a window seat, please.",
|
||
"level": "A2",
|
||
"politeness": "appropriate",
|
||
"explanation": "簡單直接地表達偏好"
|
||
},
|
||
{
|
||
"response": "A window seat would be lovely if you have one available.",
|
||
"level": "B1",
|
||
"politeness": "very_polite",
|
||
"explanation": "更加禮貌和委婉的表達方式"
|
||
}
|
||
]
|
||
},
|
||
"usage_cost": {
|
||
"hints_used": 1,
|
||
"remaining_hints": 4,
|
||
"hint_type": "free" // free, premium
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. 中翻英翻譯輔助
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/translation
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"chinese_text": "我想要一個靠窗的座位",
|
||
"context": {
|
||
"scenario": "restaurant_dining",
|
||
"formality_level": "formal",
|
||
"target_level": "A2"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"translation_id": "TRANS_20240907_001",
|
||
"translations": [
|
||
{
|
||
"english_text": "I'd like a window seat.",
|
||
"level": "A2",
|
||
"formality": "polite",
|
||
"naturalness": 5,
|
||
"explanation": "最直接和常用的表達方式"
|
||
},
|
||
{
|
||
"english_text": "Could I have a window seat, please?",
|
||
"level": "A2",
|
||
"formality": "very_polite",
|
||
"naturalness": 5,
|
||
"explanation": "更加禮貌的請求方式"
|
||
},
|
||
{
|
||
"english_text": "I would prefer a seat by the window.",
|
||
"level": "B1",
|
||
"formality": "formal",
|
||
"naturalness": 4,
|
||
"explanation": "較正式的表達方式"
|
||
}
|
||
],
|
||
"grammar_notes": [
|
||
"使用 'I'd like' 比 'I want' 更禮貌",
|
||
"'window seat' 是固定搭配,不需要冠詞"
|
||
],
|
||
"usage_cost": {
|
||
"translations_used": 1,
|
||
"remaining_translations": 9
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. 獲取詳細分析
|
||
```http
|
||
GET /api/v1/dialogues/{dialogue_id}/analysis
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
#### 查詢參數
|
||
- `turn_id`: 特定對話輪次ID (可選)
|
||
- `analysis_type`: `summary` | `detailed` | `vocabulary` (預設 `summary`)
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"dialogue_id": "DLG_20240907_001",
|
||
"analysis_summary": {
|
||
"overall_performance": {
|
||
"grammar_score": 88,
|
||
"semantic_score": 92,
|
||
"fluency_score": 85,
|
||
"pronunciation_score": 87,
|
||
"total_score": 88,
|
||
"completion_percentage": 100,
|
||
"is_perfect_score": false
|
||
},
|
||
"interaction_quality": {
|
||
"appropriateness": 95,
|
||
"naturalness": 88,
|
||
"engagement": 90,
|
||
"cultural_sensitivity": 92
|
||
}
|
||
},
|
||
"turn_by_turn_analysis": [
|
||
{
|
||
"turn_number": 1,
|
||
"user_message": "Yes, I have a reservation under Chen for 8 PM for two people.",
|
||
"analysis": {
|
||
"scores": {
|
||
"grammar": 90,
|
||
"semantic": 95,
|
||
"fluency": 85,
|
||
"pronunciation": 88
|
||
},
|
||
"feedback": {
|
||
"positive_aspects": [
|
||
"Perfect use of formal register",
|
||
"All necessary information included",
|
||
"Natural sentence structure"
|
||
],
|
||
"areas_for_improvement": [
|
||
"Consider using 'please' for extra politeness"
|
||
],
|
||
"grammar_analysis": {
|
||
"errors": [],
|
||
"complexity_level": "A2",
|
||
"sentence_patterns": ["declarative_affirmative"]
|
||
}
|
||
},
|
||
"vocabulary_usage": [
|
||
{
|
||
"word": "reservation",
|
||
"correctness": "perfect",
|
||
"level": "A2",
|
||
"context_score": 5,
|
||
"frequency": "high"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"learning_outcomes": {
|
||
"vocabulary_progress": {
|
||
"words_practiced": 12,
|
||
"words_used_correctly": 11,
|
||
"new_words_encountered": 4,
|
||
"words_to_review": ["appetizer", "dessert"]
|
||
},
|
||
"skill_development": {
|
||
"improved_areas": ["formal_requests", "restaurant_vocabulary"],
|
||
"mastery_achieved": ["basic_reservation_language"],
|
||
"next_focus": ["ordering_specific_dishes"]
|
||
},
|
||
"achievement_progress": {
|
||
"dialogue_completion": true,
|
||
"perfect_turns": 3,
|
||
"vocabulary_milestone": false,
|
||
"fluency_improvement": true
|
||
}
|
||
},
|
||
"personalized_recommendations": [
|
||
"Practice pronunciation of 'th' sounds in words like 'thank you'",
|
||
"Learn more specific food vocabulary for ordering",
|
||
"Try more complex sentence structures for B1 level"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6. 結束對話
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/complete
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"completion_type": "natural", // natural, forced, timeout
|
||
"user_rating": 4, // 1-5, user satisfaction
|
||
"feedback": "Great practice session!"
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"completion_summary": {
|
||
"dialogue_id": "DLG_20240907_001",
|
||
"scenario_name": "餐廳預約與點餐",
|
||
"duration_seconds": 420,
|
||
"turns_completed": 8,
|
||
"all_objectives_met": true,
|
||
"completion_type": "natural"
|
||
},
|
||
"performance_summary": {
|
||
"final_score": 88,
|
||
"grade": "B+",
|
||
"is_perfect_dialogue": false,
|
||
"best_turn_score": 95,
|
||
"average_response_time": 12.5,
|
||
"vocabulary_accuracy": 0.92
|
||
},
|
||
"rewards_earned": {
|
||
"experience_points": 150,
|
||
"score_points": 88,
|
||
"diamonds": 10,
|
||
"achievements_unlocked": [
|
||
{
|
||
"achievement_id": "restaurant_master",
|
||
"name": "餐廳對話專家",
|
||
"description": "完成餐廳場景對話"
|
||
}
|
||
]
|
||
},
|
||
"learning_progress": {
|
||
"vocabulary_advances": [
|
||
{
|
||
"word": "reservation",
|
||
"old_level": "learning",
|
||
"new_level": "familiar"
|
||
}
|
||
],
|
||
"skill_improvements": [
|
||
"formal_conversation",
|
||
"restaurant_etiquette"
|
||
]
|
||
},
|
||
"next_recommendations": {
|
||
"suggested_scenarios": [
|
||
"SC_Restaurant_02", // 更高級餐廳場景
|
||
"SC_Shopping_01" // 購物場景
|
||
],
|
||
"focus_areas": [
|
||
"complex_sentence_structures",
|
||
"polite_expressions"
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 7. 暫停/恢復對話
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/pause
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/resume
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
### 8. 獲取對話歷史
|
||
```http
|
||
GET /api/v1/dialogues/history
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
#### 查詢參數
|
||
- `scenario_id`: 特定場景ID (可選)
|
||
- `date_from`: 開始日期 (可選)
|
||
- `date_to`: 結束日期 (可選)
|
||
- `min_score`: 最低分數 (可選)
|
||
- `page`: 頁碼 (預設 1)
|
||
- `limit`: 每頁筆數 (預設 20)
|
||
|
||
## 🎯 對話評分系統
|
||
|
||
### 評分維度
|
||
| 維度 | 權重 | 評分標準 |
|
||
|------|------|----------|
|
||
| **Grammar** | 25% | 語法正確性和複雜度 |
|
||
| **Semantic** | 30% | 語義適切性和理解度 |
|
||
| **Fluency** | 25% | 流暢度和自然性 |
|
||
| **Pronunciation** | 20% | 發音準確度 (語音輸入) |
|
||
|
||
### 分數等級
|
||
- **90-100**: A+ (完美) - 滿星對話
|
||
- **80-89**: B+ (優秀)
|
||
- **70-79**: B (良好)
|
||
- **60-69**: C (及格)
|
||
- **<60**: D (需改進)
|
||
|
||
## 🔧 錯誤處理
|
||
|
||
### 對話相關錯誤
|
||
| 錯誤碼 | HTTP狀態 | 描述 | 處理建議 |
|
||
|--------|----------|------|----------|
|
||
| `DIALOGUE_NOT_FOUND` | 404 | 對話記錄不存在 | 檢查對話ID或重新開始 |
|
||
| `SCENARIO_NOT_FOUND` | 404 | 場景不存在 | 檢查場景ID |
|
||
| `DIALOGUE_EXPIRED` | 410 | 對話已過期 | 重新開始對話 |
|
||
| `INSUFFICIENT_LIFE_POINTS` | 403 | 命條不足 | 購買命條或等待恢復 |
|
||
| `AI_SERVICE_UNAVAILABLE` | 503 | AI服務暫時無法使用 | 稍後重試 |
|
||
| `RESPONSE_GENERATION_FAILED` | 500 | 回應生成失敗 | 重新發送訊息 |
|
||
| `HINT_LIMIT_EXCEEDED` | 429 | 提示使用次數超限 | 購買更多提示或明日重置 |
|
||
|
||
## 🧪 測試範例
|
||
|
||
### 開始對話
|
||
```bash
|
||
curl -X POST "https://api.dramaling.com/api/v1/dialogues/start" \
|
||
-H "Authorization: Bearer <access_token>" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"scenario_id": "SC_Restaurant_01", "practice_mode": "guided"}'
|
||
```
|
||
|
||
### 發送訊息
|
||
```bash
|
||
curl -X POST "https://api.dramaling.com/api/v1/dialogues/DLG_123/message" \
|
||
-H "Authorization: Bearer <access_token>" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"message": "I have a reservation under Smith.", "message_type": "text"}'
|
||
```
|
||
|
||
---
|
||
|
||
**模組負責人**: AI團隊 + 後端團隊
|
||
**最後更新**: 2024年9月7日
|
||
**相關文檔**: [用戶管理API](./user-management.md), [遊戲化系統API](./gamification.md) |