# 🎯 個人化高價值詞彙判定系統 - 詳細開發計劃

**專案**: DramaLing 英語學習平台
**功能**: 個人化高價值詞彙智能判定
**計劃版本**: v1.0
**建立日期**: 2025-01-18
**預計開發時程**: 2週

---

## 📋 **問題分析與目標**

### 🚨 **現有問題**
**當前實現位置**: `/backend/DramaLing.Api/Services/GeminiService.cs:95`
```csharp
// 目前的固定判定邏輯
"3. 標記B1以上詞彙為高價值"
```

**問題分析**:
- **A1 學習者**: 看不到 A2 詞彙的學習價值（應該對他們很重要）
- **C1 學習者**: 被 B1 詞彙干擾（對他們太簡單）
- **缺乏個人化**: 一刀切設計不符合個別學習需求
- **學習效果差**: 無法提供適當的挑戰程度

### 🎯 **設計目標**
```
新邏輯: 高價值詞彙 = 學習者當前程度 + 1~2 階級
```

**預期效果**:
| 學習者程度 | 當前標記為高價值 | 新標記為高價值 | 改善效果 |
|-----------|----------------|--------------|----------|
| A1 | B1, B2, C1, C2 | **A2, B1** | 更實用的學習目標 |
| A2 | B1, B2, C1, C2 | **B1, B2** | 適當的進階挑戰   |
| B1 | B1, B2, C1, C2 | **B2, C1** | 避免重複簡單詞彙 |
| B2 | B1, B2, C1, C2 | **C1**     | 避免重複簡單詞彙 |
| C1 | B1, B2, C1, C2 | **C1, C2** | 專注高階詞彙精進 |
| C2 | B1, B2, C1, C2 | **C1, C2** | 專注高階詞彙精進 |

---

## 🛠️ **詳細開發計劃**

## **📋 Phase 1: 資料模型擴充 (第1-2天)**

### **1.1 User 實體擴充**
**檔案**: `/backend/DramaLing.Api/Models/Entities/User.cs`
**當前行數**: 30行 (Preferences 欄位後)

**新增欄位**:
```csharp
// 在第30行 public Dictionary<string, object> Preferences { get; set; } = new(); 後新增

[MaxLength(10)]
public string EnglishLevel { get; set; } = "A2"; // A1, A2, B1, B2, C1, C2

public DateTime LevelUpdatedAt { get; set; } = DateTime.UtcNow;

public bool IsLevelVerified { get; set; } = false; // 是否通過測試驗證

[MaxLength(500)]
public string? LevelNotes { get; set; } // 程度設定備註
```

### **1.2 資料庫遷移**
**執行指令**:
```bash
# 在 /backend/DramaLing.Api/ 目錄下執行
dotnet ef migrations add AddUserEnglishLevel
dotnet ef database update
```

**生成的遷移檔案**: `/backend/DramaLing.Api/Migrations/{timestamp}_AddUserEnglishLevel.cs`

### **1.3 API 請求模型更新**
**檔案**: `/backend/DramaLing.Api/Controllers/AIController.cs`
**位置**: 第1433行附近的 AnalyzeSentenceRequest 類別

**當前結構**:
```csharp
public class AnalyzeSentenceRequest
{
    public string InputText { get; set; } = string.Empty;
    public bool ForceRefresh { get; set; } = false;
    public string AnalysisMode { get; set; } = "full";
}
```

**修改後**:
```csharp
public class AnalyzeSentenceRequest
{
    public string InputText { get; set; } = string.Empty;
    public string UserLevel { get; set; } = "A2"; // 新增：用戶英語程度
    public bool ForceRefresh { get; set; } = false;
    public string AnalysisMode { get; set; } = "full";
}
```

---

## **📋 Phase 2: 智能判定邏輯建立 (第3-5天)**

### **2.1 建立 CEFR 等級服務**
**新檔案**: `/backend/DramaLing.Api/Services/CEFRLevelService.cs`

```csharp
using System;

namespace DramaLing.Api.Services;

public static class CEFRLevelService
{
    private static readonly string[] Levels = { "A1", "A2", "B1", "B2", "C1", "C2" };

    /// <summary>
    /// 取得 CEFR 等級的數字索引
    /// </summary>
    public static int GetLevelIndex(string level)
    {
        if (string.IsNullOrEmpty(level)) return 1; // 預設 A2
        return Array.IndexOf(Levels, level.ToUpper());
    }

    /// <summary>
    /// 判定詞彙對特定用戶是否為高價值
    /// 規則：比用戶程度高 1-2 級的詞彙為高價值
    /// </summary>
    public static bool IsHighValueForUser(string wordLevel, string userLevel)
    {
        var userIndex = GetLevelIndex(userLevel);
        var wordIndex = GetLevelIndex(wordLevel);

        // 無效等級處理
        if (userIndex == -1 || wordIndex == -1) return false;

        // 高價值 = 比用戶程度高 1-2 級
        return wordIndex >= userIndex + 1 && wordIndex <= userIndex + 2;
    }

    /// <summary>
    /// 取得用戶的目標學習等級範圍
    /// </summary>
    public static string GetTargetLevelRange(string userLevel)
    {
        var userIndex = GetLevelIndex(userLevel);
        if (userIndex == -1) return "B1-B2";

        var targetMin = Levels[Math.Min(userIndex + 1, Levels.Length - 1)];
        var targetMax = Levels[Math.Min(userIndex + 2, Levels.Length - 1)];

        return targetMin == targetMax ? targetMin : $"{targetMin}-{targetMax}";
    }

    /// <summary>
    /// 取得下一個等級
    /// </summary>
    public static string GetNextLevel(string currentLevel, int steps = 1)
    {
        var currentIndex = GetLevelIndex(currentLevel);
        if (currentIndex == -1) return "B1";

        var nextIndex = Math.Min(currentIndex + steps, Levels.Length - 1);
        return Levels[nextIndex];
    }
}
```

### **2.2 更新 GeminiService**
**檔案**: `/backend/DramaLing.Api/Services/GeminiService.cs`
**修改位置**: 第54行的 `AnalyzeSentenceAsync` 方法

**當前方法簽名**:
```csharp
public async Task<SentenceAnalysisResponse> AnalyzeSentenceAsync(string inputText)
```

**修改後簽名**:
```csharp
public async Task<SentenceAnalysisResponse> AnalyzeSentenceAsync(
    string inputText,
    string userLevel = "A2")
```

**Prompt 動態化 (第63-98行)**:
```csharp
// 替換現有的固定 prompt
private string BuildSentenceAnalysisPrompt(string inputText, string userLevel)
{
    var targetRange = CEFRLevelService.GetTargetLevelRange(userLevel);

    return $@"
請分析以下英文句子，提供完整的分析：

句子：{inputText}
學習者程度：{userLevel}

請按照以下JSON格式回應，不要包含任何其他文字：

{{
  ""translation"": ""自然流暢的繁體中文翻譯"",
  ""explanation"": ""詳細解釋句子的語法結構、詞彙特點、使用場景和學習要點"",
  ""grammarCorrection"": {{
    ""hasErrors"": false,
    ""originalText"": ""{inputText}"",
    ""correctedText"": null,
    ""corrections"": []
  }},
  ""highValueWords"": [""重要詞彙1"", ""重要詞彙2""],
  ""wordAnalysis"": {{
    ""單字"": {{
      ""translation"": ""中文翻譯"",
      ""definition"": ""英文定義"",
      ""partOfSpeech"": ""詞性"",
      ""pronunciation"": ""音標"",
      ""isHighValue"": true,
      ""difficultyLevel"": ""CEFR等級""
    }}
  }}
}}

要求：
1. 翻譯要自然流暢，符合中文語法
2. 解釋要具體有用，不要空泛
3. **基於學習者程度({userLevel})，標記 {targetRange} 等級的詞彙為高價值**
4. 如有語法錯誤請指出並修正
5. 確保JSON格式正確

高價值判定邏輯：
- 學習者程度: {userLevel}
- 高價值範圍: {targetRange}
- 太簡單的詞彙(≤{userLevel})不要標記為高價值
- 太難的詞彙(>{targetRange})謹慎標記
- 重點關注 {targetRange} 範圍內的詞彙
";
}
```

### **2.3 後處理邏輯新增**
```csharp
// 在 AnalyzeSentenceAsync 方法中新增後處理
private SentenceAnalysisResponse PostProcessHighValueWords(
    SentenceAnalysisResponse result,
    string userLevel)
{
    // 二次驗證高價值詞彙判定，確保 AI 判定正確
    foreach (var wordPair in result.WordAnalysis)
    {
        var word = wordPair.Value;
        word.IsHighValue = CEFRLevelService.IsHighValueForUser(
            word.DifficultyLevel,
            userLevel);
    }

    // 更新高價值詞彙列表
    result.HighValueWords = result.WordAnalysis
        .Where(w => w.Value.IsHighValue)
        .Select(w => w.Key)
        .ToList();

    return result;
}
```

---

## **📋 Phase 3: Controller 層整合 (第6-7天)**

### **3.1 更新 AnalyzeSentence API**
**檔案**: `/backend/DramaLing.Api/Controllers/AIController.cs`
**位置**: 第501行的 `AnalyzeSentence` 方法

**在第566行前新增用戶程度取得邏輯**:
```csharp
// 第560行後，第566行 aiAnalysis 調用前新增：

// 取得用戶英語程度
string userLevel = request.UserLevel;
if (string.IsNullOrEmpty(userLevel))
{
    // 如果 API 請求未提供程度，嘗試從用戶資料取得
    var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
    if (userId.HasValue)
    {
        var user = await _context.Users.FindAsync(userId.Value);
        userLevel = user?.EnglishLevel ?? "A2";
        _logger.LogInformation("Retrieved user level from database: {UserLevel}", userLevel);
    }
    else
    {
        userLevel = "A2"; // 未登入用戶預設程度
        _logger.LogInformation("Using default level for anonymous user: A2");
    }
}

_logger.LogInformation("Using user level for analysis: {UserLevel}", userLevel);
```

**修改第566行的 AI 調用**:
```csharp
// 原本：
// var aiAnalysis = await _geminiService.AnalyzeSentenceAsync(request.InputText);

// 修改為：
var aiAnalysis = await _geminiService.AnalyzeSentenceAsync(request.InputText, userLevel);
```

### **3.2 回應資料增強**
**位置**: 第573行的 baseResponseData 物件

**新增用戶程度相關資訊**:
```csharp
var baseResponseData = new
{
    AnalysisId = Guid.NewGuid(),
    InputText = request.InputText,
    UserLevel = userLevel, // 新增：顯示使用的程度
    HighValueCriteria = CEFRLevelService.GetTargetLevelRange(userLevel), // 新增：顯示高價值判定範圍
    GrammarCorrection = aiAnalysis.GrammarCorrection,
    SentenceMeaning = new
    {
        Translation = aiAnalysis.Translation,
        Explanation = aiAnalysis.Explanation
    },
    FinalAnalysisText = finalText ?? request.InputText,
    WordAnalysis = aiAnalysis.WordAnalysis,
    HighValueWords = aiAnalysis.HighValueWords,
    PhrasesDetected = new object[0]
};
```

---

## **📋 Phase 4: 前端個人化體驗 (第8-11天)**

### **4.1 建立用戶程度設定頁面**
**新檔案**: `/frontend/app/settings/page.tsx`

```typescript
'use client'
import { useState, useEffect } from 'react'

interface LanguageLevel {
  value: string;
  label: string;
  description: string;
  examples: string[];
}

export default function SettingsPage() {
  const [userLevel, setUserLevel] = useState('A2');
  const [isLoading, setIsLoading] = useState(false);

  const levels: LanguageLevel[] = [
    {
      value: 'A1',
      label: 'A1 - 初學者',
      description: '能理解基本詞彙和簡單句子',
      examples: ['hello', 'good', 'house', 'eat', 'happy']
    },
    {
      value: 'A2',
      label: 'A2 - 基礎',
      description: '能處理日常對話和常見主題',
      examples: ['important', 'difficult', 'interesting', 'beautiful', 'understand']
    },
    {
      value: 'B1',
      label: 'B1 - 中級',
      description: '能理解清楚標準語言的要點',
      examples: ['analyze', 'opportunity', 'environment', 'responsibility', 'development']
    },
    {
      value: 'B2',
      label: 'B2 - 中高級',
      description: '能理解複雜文本的主要內容',
      examples: ['sophisticated', 'implications', 'comprehensive', 'substantial', 'methodology']
    },
    {
      value: 'C1',
      label: 'C1 - 高級',
      description: '能流利表達，理解含蓄意思',
      examples: ['meticulous', 'predominantly', 'intricate', 'corroborate', 'paradigm']
    },
    {
      value: 'C2',
      label: 'C2 - 精通',
      description: '接近母語水平',
      examples: ['ubiquitous', 'ephemeral', 'perspicacious', 'multifarious', 'idiosyncratic']
    }
  ];

  const saveUserLevel = async () => {
    setIsLoading(true);
    try {
      // 保存到本地存儲
      localStorage.setItem('userEnglishLevel', userLevel);

      // 如果用戶已登入，也保存到伺服器
      const token = localStorage.getItem('authToken');
      if (token) {
        await fetch('/api/user/update-level', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${token}`
          },
          body: JSON.stringify({ englishLevel: userLevel })
        });
      }

      alert('✅ 程度設定已保存！系統將為您提供個人化的詞彙標記。');
    } catch (error) {
      console.error('Error saving user level:', error);
      alert('❌ 保存失敗，請稍後再試');
    } finally {
      setIsLoading(false);
    }
  };

  const getHighValueRange = (level: string) => {
    const ranges = {
      'A1': 'A2-B1',
      'A2': 'B1-B2',
      'B1': 'B2-C1',
      'B2': 'C1-C2',
      'C1': 'C1-C2',
      'C2': 'C1-C2'
    };
    return ranges[level as keyof typeof ranges] || 'B1-B2';
  };

  return (
    <div className="max-w-4xl mx-auto p-6">
      <div className="mb-8">
        <h1 className="text-3xl font-bold mb-4">🎯 英語程度設定</h1>
        <p className="text-gray-600">
          設定您的英語程度，系統將為您提供個人化的詞彙學習建議。
          設定後，我們會重點標記比您目前程度高1-2級的詞彙。
        </p>
      </div>

      <div className="grid gap-4 mb-8">
        {levels.map(level => (
          <label
            key={level.value}
            className={`
              p-6 border-2 rounded-xl cursor-pointer transition-all hover:shadow-md
              ${userLevel === level.value
                ? 'border-blue-500 bg-blue-50 shadow-md'
                : 'border-gray-200 hover:border-gray-300'
              }
            `}
          >
            <input
              type="radio"
              name="level"
              value={level.value}
              checked={userLevel === level.value}
              onChange={(e) => setUserLevel(e.target.value)}
              className="sr-only"
            />

            <div className="flex items-start justify-between">
              <div className="flex-1">
                <div className="font-bold text-xl text-gray-800 mb-2">
                  {level.label}
                </div>
                <div className="text-gray-600 mb-3">
                  {level.description}
                </div>
                <div className="flex flex-wrap gap-2">
                  {level.examples.map(example => (
                    <span
                      key={example}
                      className="px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm"
                    >
                      {example}
                    </span>
                  ))}
                </div>
              </div>

              {userLevel === level.value && (
                <div className="ml-4">
                  <div className="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center">
                    <svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20">
                      <path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
                    </svg>
                  </div>
                </div>
              )}
            </div>
          </label>
        ))}
      </div>

      {/* 個人化效果預覽 */}
      <div className="bg-gradient-to-r from-blue-50 to-indigo-50 p-6 rounded-xl mb-8">
        <h3 className="font-bold text-lg text-blue-800 mb-3">
          💡 您的個人化學習效果預覽
        </h3>
        <div className="grid md:grid-cols-2 gap-4">
          <div>
            <h4 className="font-semibold text-blue-700 mb-2">高價值詞彙範圍</h4>
            <p className="text-blue-600">
              系統將重點標記 <span className="font-bold">{getHighValueRange(userLevel)}</span> 等級的詞彙
            </p>
          </div>
          <div>
            <h4 className="font-semibold text-blue-700 mb-2">學習建議</h4>
            <p className="text-blue-600 text-sm">
              專注於比您目前程度({userLevel})高1-2級的詞彙，既有挑戰性又不會太困難
            </p>
          </div>
        </div>
      </div>

      <button
        onClick={saveUserLevel}
        disabled={isLoading}
        className={`
          w-full py-4 rounded-xl font-semibold text-lg transition-all
          ${isLoading
            ? 'bg-gray-300 text-gray-500 cursor-not-allowed'
            : 'bg-blue-500 text-white hover:bg-blue-600 shadow-lg hover:shadow-xl'
          }
        `}
      >
        {isLoading ? '⏳ 保存中...' : '✅ 保存程度設定'}
      </button>

      <div className="mt-4 text-center">
        <p className="text-sm text-gray-500">
          💡 提示: 您隨時可以回到這裡調整程度設定
        </p>
      </div>
    </div>
  );
}
```

### **4.2 更新導航選單**
**檔案**: `/frontend/components/Navigation.tsx`

**新增設定頁面連結**:
```typescript
// 在現有導航項目中新增
<Link
  href="/settings"
  className={`px-3 py-2 rounded-md text-sm font-medium ${
    pathname === '/settings'
      ? 'bg-blue-100 text-blue-700'
      : 'text-gray-600 hover:text-gray-900'
  }`}
>
  ⚙️ 設定
</Link>
```

### **4.3 修改句子分析頁面**
**檔案**: `/frontend/app/generate/page.tsx`
**修改位置**: 第39行的 `handleAnalyzeSentence` 函數

**新增用戶程度取得邏輯**:
```typescript
const handleAnalyzeSentence = async () => {
    if (!textInput?.trim()) {
      alert('🔍 請輸入要分析的句子')
      return
    }

    // 取得用戶設定的程度
    const userLevel = localStorage.getItem('userEnglishLevel') || 'A2';

    console.log('🎯 使用用戶程度:', userLevel);
    console.log('✅ 開始分析，設定 loading 狀態')
    setIsAnalyzing(true)

    try {
      console.log('🌐 發送API請求到:', 'http://localhost:5000/api/ai/analyze-sentence')
      const response = await fetch('http://localhost:5000/api/ai/analyze-sentence', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          inputText: textInput,
          userLevel: userLevel, // 傳遞用戶程度
          analysisMode: 'full'
        })
      })

      // ... 其餘現有邏輯保持不變
    }
    // ... catch 和 finally 保持不變
};
```

### **4.4 個人化詞彙標記顯示**
**檔案**: `/frontend/app/generate/page.tsx`
**位置**: 詞彙顯示區域 (分析結果視圖中)

**新增個人化詞彙標記組件**:
```typescript
// 新增輔助函數
const getLevelIndex = (level: string): number => {
  const levels = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'];
  return levels.indexOf(level.toUpperCase());
};

const getWordValueStyle = (wordLevel: string, userLevel: string) => {
  const userIndex = getLevelIndex(userLevel);
  const wordIndex = getLevelIndex(wordLevel);

  if (wordIndex <= userIndex) {
    return {
      bg: 'bg-green-100 border-green-300',
      text: 'text-green-800',
      label: '已掌握',
      icon: '✅'
    };
  } else if (wordIndex === userIndex + 1) {
    return {
      bg: 'bg-yellow-100 border-yellow-300',
      text: 'text-yellow-800',
      label: '適中挑戰',
      icon: '🎯'
    };
  } else if (wordIndex === userIndex + 2) {
    return {
      bg: 'bg-orange-100 border-orange-300',
      text: 'text-orange-800',
      label: '高挑戰',
      icon: '🚀'
    };
  } else {
    return {
      bg: 'bg-red-100 border-red-300',
      text: 'text-red-800',
      label: '太難',
      icon: '⚠️'
    };
  }
};

// 詞彙顯示組件
function WordAnalysisCard({ word, analysis, userLevel }: Props) {
  const style = getWordValueStyle(analysis.difficultyLevel, userLevel);

  return (
    <div className={`p-4 rounded-lg border-2 ${style.bg} ${style.text}`}>
      <div className="flex items-center justify-between mb-2">
        <span className="font-bold text-lg">{word}</span>
        <div className="flex items-center gap-2">
          <span className="text-sm">{analysis.difficultyLevel}</span>
          <span className="text-xs px-2 py-1 rounded-full bg-white bg-opacity-50">
            {style.icon} {style.label}
          </span>
        </div>
      </div>

      <div className="text-sm space-y-1">
        <p><strong>翻譯:</strong> {analysis.translation}</p>
        <p><strong>發音:</strong> {analysis.pronunciation}</p>
        <p><strong>定義:</strong> {analysis.definition}</p>
      </div>

      {analysis.isHighValue && (
        <div className="mt-3 p-2 bg-white bg-opacity-30 rounded text-xs">
          💎 <strong>高價值詞彙</strong> - 適合您目前程度的學習重點
        </div>
      )}
    </div>
  );
}
```

### **4.5 新增程度指示器**
**檔案**: `/frontend/app/generate/page.tsx`
**位置**: 使用次數顯示區域後 (第306行後)

```typescript
{/* 個人化程度指示器 */}
<div className="text-center text-sm text-gray-600 mt-2">
  {(() => {
    const userLevel = localStorage.getItem('userEnglishLevel') || 'A2';
    const targetRange = getTargetLevelRange(userLevel);
    return (
      <div className="flex items-center justify-center gap-2">
        <span>🎯 您的程度: {userLevel}</span>
        <span className="text-gray-400">|</span>
        <span>💎 高價值範圍: {targetRange}</span>
        <Link
          href="/settings"
          className="text-blue-500 hover:text-blue-700 ml-2"
        >
          調整 ⚙️
        </Link>
      </div>
    );
  })()}
</div>
```

---

## **📋 Phase 5: 進階功能 (第12-14天)**

### **5.1 建立用戶程度更新 API**
**檔案**: `/backend/DramaLing.Api/Controllers/UsersController.cs` (可能需要新建)

```csharp
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class UsersController : ControllerBase
{
    private readonly DramaLingDbContext _context;
    private readonly IAuthService _authService;

    [HttpPost("update-level")]
    public async Task<ActionResult> UpdateUserLevel([FromBody] UpdateLevelRequest request)
    {
        var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
        if (userId == null) return Unauthorized();

        var user = await _context.Users.FindAsync(userId.Value);
        if (user == null) return NotFound();

        // 驗證等級有效性
        var validLevels = new[] { "A1", "A2", "B1", "B2", "C1", "C2" };
        if (!validLevels.Contains(request.EnglishLevel.ToUpper()))
        {
            return BadRequest("Invalid English level");
        }

        user.EnglishLevel = request.EnglishLevel.ToUpper();
        user.LevelUpdatedAt = DateTime.UtcNow;
        user.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        return Ok(new {
            Success = true,
            Data = new {
                UserId = user.Id,
                EnglishLevel = user.EnglishLevel,
                UpdatedAt = user.LevelUpdatedAt
            },
            Message = "User level updated successfully"
        });
    }
}

public class UpdateLevelRequest
{
    public string EnglishLevel { get; set; } = string.Empty;
}
```

### **5.2 程度建議系統**
**檔案**: `/frontend/components/LevelRecommendation.tsx` (新建)

```typescript
interface LevelRecommendationProps {
  userLevel: string;
  analysisResult: any;
}

export function LevelRecommendation({ userLevel, analysisResult }: LevelRecommendationProps) {
  const recommendations = {
    A1: {
      focus: "先掌握基礎詞彙，建立信心",
      nextGoal: "目標掌握所有 A2 詞彙",
      tips: ["多看簡單對話", "重複練習基礎詞彙", "先不要急於挑戰難詞"]
    },
    A2: {
      focus: "挑戰 B1 詞彙，擴展詞彙量",
      nextGoal: "準備進入中級程度",
      tips: ["開始接觸新聞", "學習片語搭配", "練習複雜句型"]
    },
    B1: {
      focus: "精進 B2 詞彙，提升表達精準度",
      nextGoal: "達到中高級水平",
      tips: ["閱讀專業文章", "學習學術詞彙", "練習論述表達"]
    },
    B2: {
      focus: "挑戰 C1 詞彙，培養高階表達",
      nextGoal: "邁向高級程度",
      tips: ["深度閱讀", "學習抽象概念詞彙", "練習批判性思考表達"]
    },
    C1: {
      focus: "精進 C2 詞彙，達到接近母語水平",
      nextGoal: "達到精通程度",
      tips: ["文學作品閱讀", "學習專業術語", "練習修辭技巧"]
    },
    C2: {
      focus: "保持語言敏感度，精進表達細節",
      nextGoal: "維持高水準",
      tips: ["關注語言變化", "學習方言俚語", "練習創意表達"]
    }
  };

  const rec = recommendations[userLevel as keyof typeof recommendations] || recommendations.A2;

  return (
    <div className="bg-gradient-to-r from-purple-50 to-pink-50 p-6 rounded-xl">
      <h3 className="font-bold text-lg text-purple-800 mb-4">
        🎯 基於您程度({userLevel})的個人化建議
      </h3>

      <div className="grid md:grid-cols-2 gap-4">
        <div>
          <h4 className="font-semibold text-purple-700 mb-2">當前重點</h4>
          <p className="text-purple-600">{rec.focus}</p>
        </div>
        <div>
          <h4 className="font-semibold text-purple-700 mb-2">下階段目標</h4>
          <p className="text-purple-600">{rec.nextGoal}</p>
        </div>
      </div>

      <div className="mt-4">
        <h4 className="font-semibold text-purple-700 mb-2">學習技巧</h4>
        <ul className="text-purple-600 text-sm space-y-1">
          {rec.tips.map((tip, index) => (
            <li key={index} className="flex items-center gap-2">
              <span className="text-purple-400">•</span>
              {tip}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}
```

---

## **📋 Phase 6: 測試與驗證 (第13-14天)**

### **6.1 單元測試**
**新檔案**: `/backend/DramaLing.Api.Tests/Services/CEFRLevelServiceTests.cs`

```csharp
using Xunit;
using DramaLing.Api.Services;

public class CEFRLevelServiceTests
{
    [Theory]
    [InlineData("A2", "A1", false)] // 太簡單
    [InlineData("A2", "A2", false)] // 同等級
    [InlineData("A2", "B1", true)]  // +1級，高價值
    [InlineData("A2", "B2", true)]  // +2級，高價值
    [InlineData("A2", "C1", false)] // 太難
    public void IsHighValueForUser_ShouldReturnExpectedResult(
        string userLevel, string wordLevel, bool expected)
    {
        var result = CEFRLevelService.IsHighValueForUser(wordLevel, userLevel);
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("A1", "A2-B1")]
    [InlineData("A2", "B1-B2")]
    [InlineData("B1", "B2-C1")]
    [InlineData("C1", "C2")]
    public void GetTargetLevelRange_ShouldReturnCorrectRange(
        string userLevel, string expectedRange)
    {
        var result = CEFRLevelService.GetTargetLevelRange(userLevel);
        Assert.Equal(expectedRange, result);
    }
}
```

### **6.2 整合測試腳本**
**新檔案**: `/test-personalized-analysis.sh`

```bash
#!/bin/bash

echo "🧪 測試個人化高價值詞彙判定"

# 測試句子
TEST_SENTENCE="The sophisticated analysis reveals important implications for understanding complex linguistic patterns."

echo "📝 測試句子: $TEST_SENTENCE"
echo ""

# 測試不同程度用戶
for level in A1 A2 B1 B2 C1; do
    echo "🎯 測試 $level 程度用戶："

    response=$(curl -s -X POST http://localhost:5000/api/ai/analyze-sentence \
      -H "Content-Type: application/json" \
      -d "{\"inputText\": \"$TEST_SENTENCE\", \"userLevel\": \"$level\"}")

    # 提取高價值詞彙和判定範圍
    highValueWords=$(echo $response | jq -r '.data.highValueWords[]?' 2>/dev/null | tr '\n' ',' | sed 's/,$//')
    criteria=$(echo $response | jq -r '.data.highValueCriteria?' 2>/dev/null)

    echo "   高價值範圍: $criteria"
    echo "   標記詞彙: $highValueWords"
    echo ""
done

echo "✅ 測試完成！檢查每個程度用戶的高價值詞彙是否不同"
```

---

## **⏰ 開發時程表**

| 天數 | 階段 | 主要任務 | 預計工時 | 檔案涉及 |
|------|------|----------|----------|----------|
| Day 1-2 | **資料模型** | User 實體擴充、API 擴充、資料庫遷移 | 12h | `User.cs`, `AIController.cs` |
| Day 3-5 | **判定邏輯** | CEFRLevelService、GeminiService 重構 | 16h | `CEFRLevelService.cs`, `GeminiService.cs` |
| Day 6-7 | **Controller 整合** | API 邏輯整合、錯誤處理 | 10h | `AIController.cs` |
| Day 8-10 | **前端設定頁** | 程度設定介面、導航整合 | 18h | `settings/page.tsx`, `Navigation.tsx` |
| Day 11 | **前端分析整合** | generate 頁面修改、個人化顯示 | 8h | `generate/page.tsx` |
| Day 12-13 | **測試開發** | 單元測試、整合測試、腳本 | 12h | 測試檔案 |
| Day 14 | **優化除錯** | 性能調整、UI 優化、文檔更新 | 6h | 各檔案 |

**總計**: 82 工時 (約2週全職開發)

---

## **🎯 驗收標準**

### **功能需求驗收**
- [ ] **個人化判定**: A2 用戶看到 B1-B2 詞彙為高價值，C1 用戶只看到 C2 為高價值
- [ ] **設定頁面**: 用戶可以選擇並保存 A1-C2 程度
- [ ] **即時生效**: 程度修改後，下次分析立即使用新程度
- [ ] **回退機制**: 未設定程度的用戶預設為 A2
- [ ] **本地存儲**: 程度設定保存在 localStorage，未登入用戶也能使用

### **技術需求驗收**
- [ ] **API 相容性**: 現有前端不傳 userLevel 時仍正常運作
- [ ] **效能基準**: API 回應時間增加 < 200ms
- [ ] **錯誤處理**: 無效程度參數時優雅降級
- [ ] **資料完整性**: 用戶程度資料正確遷移和驗證
- [ ] **測試覆蓋**: 單元測試覆蓋率 > 80%

### **用戶體驗驗收**
- [ ] **視覺清晰**: 不同價值詞彙有明顯的視覺區分
- [ ] **操作直觀**: 程度設定流程簡單明確
- [ ] **回饋及時**: 程度變更後有明確的確認訊息
- [ ] **學習指導**: 提供基於程度的學習建議

---

## **🚀 部署與上線**

### **上線前檢查清單**
- [ ] 所有測試通過
- [ ] 資料庫遷移在生產環境執行
- [ ] 現有用戶資料正確設定預設程度 (A2)
- [ ] API 文檔更新完成
- [ ] 監控系統配置完成

### **上線後監控指標**
- [ ] **功能使用率**: 多少用戶設定了程度
- [ ] **學習效果**: 個人化後的詞彙點擊率變化
- [ ] **錯誤率**: 新功能相關的錯誤追蹤
- [ ] **效能影響**: API 回應時間變化

---

## **📞 風險評估與應對**

### **技術風險**
1. **AI Prompt 複雜化**: 可能影響回應品質
   - **應對**: 充分測試，準備回退機制

2. **資料庫效能**: 新增欄位可能影響查詢效能
   - **應對**: 建立適當索引，監控查詢時間

3. **前端相容性**: 新功能可能影響現有使用者體驗
   - **應對**: 向下相容設計，預設值保持原有行為

### **產品風險**
1. **用戶理解難度**: CEFR 程度對一般用戶可能太專業
   - **應對**: 提供簡單的描述和範例詞彙

2. **設定複雜性**: 增加設定可能讓產品變複雜
   - **應對**: 智能預設值，讓設定變為可選功能

---

## **📋 成功指標**

### **定量指標** (3個月後評估)
- **程度設定率**: > 60% 的活躍用戶設定了程度
- **詞彙點擊提升**: 高價值詞彙點擊率提升 > 30%
- **學習時長**: 平均學習時長提升 > 20%
- **用戶滿意度**: 功能滿意度 > 4.0/5.0

### **定性指標**
- **學習體驗**: 用戶反應詞彙推薦更精準
- **挑戰適中**: 減少「太難」或「太簡單」的反饋
- **進步感知**: 用戶感受到明確的學習進階路徑

---

**© 2025 DramaLing Development Team**
**文檔建立**: 2025-01-18
**計劃核准**: 待用戶確認