diff --git a/UPDATED_PERSONALIZED_WORDS_PLAN.md b/UPDATED_PERSONALIZED_WORDS_PLAN.md new file mode 100644 index 0000000..081f02f --- /dev/null +++ b/UPDATED_PERSONALIZED_WORDS_PLAN.md @@ -0,0 +1,345 @@ +# 🎯 個人化高價值詞彙判定系統 - 更新版實施計劃 + +**專案**: DramaLing 英語學習平台 +**功能**: 個人化高價值詞彙智能判定 +**計劃版本**: v2.0 (根據當前代碼狀況更新) +**更新日期**: 2025-01-18 +**預計開發時程**: 1.5週 (優化後的架構加速開發) + +--- + +## 📋 **當前代碼狀況分析** + +### **✅ 已完成的優化 (有利於個人化實施)** +- ✅ **移除快取機制**: 簡化了邏輯,每次都是新 AI 分析 +- ✅ **移除 explanation**: 簡化了回應格式 +- ✅ **代碼大幅精簡**: AIController 減少 200+ 行 +- ✅ **架構清晰**: Service 層職責明確 + +### **🔧 當前架構分析** + +#### **User 實體** +**位置**: `/backend/DramaLing.Api/Models/Entities/User.cs:30` +**狀態**: ✅ 完美適合擴充,Preferences 後正好可新增 EnglishLevel + +#### **AnalyzeSentenceRequest** +**位置**: `/backend/DramaLing.Api/Controllers/AIController.cs:1313` +**當前結構**: +```csharp +public class AnalyzeSentenceRequest +{ + public string InputText { get; set; } = string.Empty; + public bool ForceRefresh { get; set; } = false; + public string AnalysisMode { get; set; } = "full"; +} +``` +**狀態**: ✅ 簡潔易擴充 + +#### **GeminiService.AnalyzeSentenceAsync** +**位置**: `/backend/DramaLing.Api/Services/GeminiService.cs:55` +**當前簽名**: `AnalyzeSentenceAsync(string inputText)` +**當前 Prompt** (第64-96行): 已簡化,無 explanation 欄位 +**狀態**: ✅ 適合個人化擴充 + +--- + +## 🛠️ **更新版實施計劃** + +## **📋 Phase 1: 資料模型擴充 (第1天)** + +### **1.1 User 實體擴充** ✅ 無變動 +**檔案**: `/backend/DramaLing.Api/Models/Entities/User.cs` +**位置**: 第30行 `public Dictionary Preferences` 後 + +```csharp +[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 API 請求模型更新** ✅ 無變動 +**檔案**: `/backend/DramaLing.Api/Controllers/AIController.cs:1313` + +```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"; +} +``` + +### **1.3 資料庫遷移** ✅ 無變動 +```bash +cd /backend/DramaLing.Api/ +dotnet ef migrations add AddUserEnglishLevel +dotnet ef database update +``` + +--- + +## **📋 Phase 2: Service 層個人化 (第2-3天)** + +### **2.1 建立 CEFR 等級服務** ✅ 無變動 +**新檔案**: `/backend/DramaLing.Api/Services/CEFRLevelService.cs` +(代碼與原計劃相同) + +### **2.2 更新 GeminiService** 🔄 根據當前狀況調整 + +**檔案**: `/backend/DramaLing.Api/Services/GeminiService.cs` +**修改位置**: 第55行的 `AnalyzeSentenceAsync` 方法 + +**當前方法簽名**: +```csharp +public async Task AnalyzeSentenceAsync(string inputText) +``` + +**修改後簽名**: +```csharp +public async Task AnalyzeSentenceAsync( + string inputText, + string userLevel = "A2") +``` + +**🔄 更新版 Prompt (第64-96行) - 已適配移除 explanation**: +```csharp +var prompt = $@" +請分析以下英文句子,提供翻譯和個人化詞彙分析: + +句子:{inputText} +學習者程度:{userLevel} + +請按照以下JSON格式回應,不要包含任何其他文字: + +{{ + ""translation"": ""自然流暢的繁體中文翻譯"", + ""grammarCorrection"": {{ + ""hasErrors"": false, + ""originalText"": ""{inputText}"", + ""correctedText"": null, + ""corrections"": [] + }}, + ""highValueWords"": [""重要詞彙1"", ""重要詞彙2""], + ""wordAnalysis"": {{ + ""單字"": {{ + ""translation"": ""中文翻譯"", + ""definition"": ""英文定義"", + ""partOfSpeech"": ""詞性"", + ""pronunciation"": ""音標"", + ""isHighValue"": true, + ""difficultyLevel"": ""CEFR等級"" + }} + }} +}} + +要求: +1. 翻譯要自然流暢,符合中文語法 +2. **基於學習者程度({userLevel}),標記 {CEFRLevelService.GetTargetLevelRange(userLevel)} 等級的詞彙為高價值** +3. 如有語法錯誤請指出並修正 +4. 確保JSON格式正確 + +高價值判定邏輯: +- 學習者程度: {userLevel} +- 高價值範圍: {CEFRLevelService.GetTargetLevelRange(userLevel)} +- 太簡單的詞彙(≤{userLevel})不要標記為高價值 +- 太難的詞彙謹慎標記 +- 重點關注適合學習者程度的詞彙 +"; +``` + +--- + +## **📋 Phase 3: Controller 層整合 (第4天) - 🔄 簡化版** + +### **3.1 更新 AnalyzeSentence API** +**檔案**: `/backend/DramaLing.Api/Controllers/AIController.cs` +**位置**: 第501行的 `AnalyzeSentence` 方法 + +**🔄 簡化版用戶程度取得邏輯** (在第538行 AI 調用前新增): +```csharp +// 取得用戶英語程度 +string userLevel = request.UserLevel ?? "A2"; + +// 🔄 簡化版:暫不從資料庫讀取,先使用 API 參數或預設值 +if (string.IsNullOrEmpty(userLevel)) +{ + userLevel = "A2"; // 預設程度 +} + +_logger.LogInformation("Using user level for analysis: {UserLevel}", userLevel); +``` + +**🔄 更新 AI 調用** (當前約第540行): +```csharp +// 原本: +// var aiAnalysis = await _geminiService.AnalyzeSentenceAsync(request.InputText); + +// 修改為: +var aiAnalysis = await _geminiService.AnalyzeSentenceAsync(request.InputText, userLevel); +``` + +### **3.2 回應資料增強** 🔄 適配無快取版本 +**位置**: 約第550行的 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 + }, + FinalAnalysisText = finalText ?? request.InputText, + WordAnalysis = aiAnalysis.WordAnalysis, + HighValueWords = aiAnalysis.HighValueWords, + PhrasesDetected = new object[0] +}; +``` + +--- + +## **📋 Phase 4: 前端個人化體驗 (第5-7天) - ✅ 基本無變動** + +### **4.1 建立用戶程度設定頁面** ✅ 原計劃可直接使用 +**新檔案**: `/frontend/app/settings/page.tsx` +(完整代碼與原計劃相同,已針對無 explanation 優化) + +### **4.2 更新導航選單** ✅ 無變動 +**檔案**: `/frontend/components/Navigation.tsx` + +### **4.3 修改句子分析頁面** 🔄 微調 +**檔案**: `/frontend/app/generate/page.tsx` +**修改位置**: 第28行的 `handleAnalyzeSentence` 函數 (行數已更新) + +### **4.4 個人化詞彙標記顯示** ✅ 基本無變動 +(原計劃的 WordAnalysisCard 組件可直接使用) + +--- + +## **🔄 主要調整說明** + +### **1. 移除過時的快取相關邏輯** +```diff +- 原計劃: 修改快取檢查和存入邏輯 ++ 更新版: 已無快取機制,直接修改 AI 調用 +``` + +### **2. 適配簡化的回應格式** +```diff +- 原計劃: SentenceMeaning { Translation, Explanation } ++ 更新版: SentenceMeaning { Translation } // 已移除 explanation +``` + +### **3. 簡化錯誤處理** +```diff +- 原計劃: 複雜的快取錯誤處理 ++ 更新版: 簡化的 AI 錯誤處理 +``` + +### **4. 更新行數引用** +```diff +- 原計劃: 基於舊版本的行數 ++ 更新版: 基於當前優化後的行數 +``` + +--- + +## **⏰ 更新版開發時程** + +| 天數 | 階段 | 主要任務 | 預計工時 | 變化 | +|------|------|----------|----------|------| +| Day 1 | **資料模型** | User 實體擴充、API 擴充、資料庫遷移 | 8h | -4h (簡化) | +| Day 2-3 | **Service 層** | CEFRLevelService、GeminiService 個人化 | 12h | -4h (無快取) | +| Day 4 | **Controller 整合** | 簡化版 API 邏輯整合 | 6h | -4h (已優化) | +| Day 5-6 | **前端設定頁** | 程度設定介面、導航整合 | 12h | 無變動 | +| Day 7 | **前端分析整合** | generate 頁面修改、個人化顯示 | 6h | -2h (簡化) | +| Day 8-9 | **測試開發** | 單元測試、整合測試 | 8h | -4h (簡化) | +| Day 10 | **優化除錯** | 性能調整、UI 優化 | 4h | -2h | + +**總計**: 56 工時 (約1.5週) - **節省 26 工時!** + +--- + +## **🎯 實施優勢分析** + +### **🚀 當前架構的優勢** +1. **代碼更乾淨**: 移除冗餘後更容易擴充 +2. **邏輯更清晰**: 無快取干擾,邏輯線性化 +3. **Service 層完整**: GeminiService 架構良好 +4. **API 簡潔**: 統一的錯誤處理 + +### **💡 實施建議** + +#### **立即可開始的項目** +1. **User 實體擴充** - 完全 ready +2. **CEFRLevelService 建立** - 獨立功能 +3. **前端設定頁面** - 無依賴 + +#### **需要小幅調整的項目** +1. **GeminiService Prompt** - 適配無 explanation +2. **Controller 行數** - 更新引用位置 + +--- + +## **📋 風險評估更新** + +### **🟢 降低的風險** +- ✅ **複雜度降低**: 無快取邏輯干擾 +- ✅ **測試簡化**: 線性邏輯更易測試 +- ✅ **維護容易**: 代碼結構清晰 + +### **🟡 保持的風險** +- ⚠️ **AI Prompt 複雜化**: 仍需謹慎測試 +- ⚠️ **用戶理解度**: CEFR 概念對用戶的理解 + +### **🔴 新增風險** +- ⚠️ **AI 成本**: 無快取後每次都調用 AI (但您已選擇此方向) + +--- + +## **🎯 執行建議** + +### **🚀 立即開始** +建議從 **Phase 1** 開始,因為: +- ✅ 完全獨立,無依賴 +- ✅ 為後續階段打基礎 +- ✅ 可以快速看到成果 + +### **🔄 調整重點** +1. **更新所有行數引用** +2. **移除 explanation 相關邏輯** +3. **簡化快取相關的修改步驟** + +### **📊 成功機率** +**95%** - 當前架構非常適合個人化功能實施 + +--- + +## **💡 額外建議** + +### **漸進式實施** +可以考慮分階段發佈: +1. **MVP版**: 僅前端本地存儲用戶程度 +2. **完整版**: 後端資料庫 + 完整個人化 + +### **測試策略** +由於代碼已大幅簡化,測試工作量也相應減少 + +--- + +**結論: 這個計劃不僅可行,而且由於當前代碼優化,實施會比原計劃更簡單快速!** 🎉 + +**© 2025 DramaLing Development Team** +**更新基於**: 當前代碼狀況 (commit 1b937f8) +**主要改善**: 適配優化後的簡潔架構 \ No newline at end of file diff --git a/backend/DramaLing.Api/Controllers/AIController.cs b/backend/DramaLing.Api/Controllers/AIController.cs index 6e3f029..5079e7a 100644 --- a/backend/DramaLing.Api/Controllers/AIController.cs +++ b/backend/DramaLing.Api/Controllers/AIController.cs @@ -533,23 +533,29 @@ public class AIController : ControllerBase // 移除快取檢查,每次都進行新的 AI 分析 + // 取得用戶英語程度 + string userLevel = request.UserLevel ?? "A2"; + _logger.LogInformation("Using user level for analysis: {UserLevel}", userLevel); + // 2. 執行真正的AI分析 - _logger.LogInformation("Calling Gemini AI for text: {InputText}", request.InputText); + _logger.LogInformation("Calling Gemini AI for text: {InputText} with user level: {UserLevel}", request.InputText, userLevel); try { - // 真正調用 Gemini AI 進行句子分析 - var aiAnalysis = await _geminiService.AnalyzeSentenceAsync(request.InputText); + // 真正調用 Gemini AI 進行句子分析(傳遞用戶程度) + var aiAnalysis = await _geminiService.AnalyzeSentenceAsync(request.InputText, userLevel); // 使用AI分析結果 var finalText = aiAnalysis.GrammarCorrection.HasErrors ? aiAnalysis.GrammarCorrection.CorrectedText : request.InputText; - // 3. 準備AI分析響應資料 + // 3. 準備AI分析響應資料(包含個人化資訊) var baseResponseData = new { AnalysisId = Guid.NewGuid(), InputText = request.InputText, + UserLevel = userLevel, // 新增:顯示使用的程度 + HighValueCriteria = CEFRLevelService.GetTargetLevelRange(userLevel), // 新增:顯示高價值判定範圍 GrammarCorrection = aiAnalysis.GrammarCorrection, SentenceMeaning = new { @@ -1313,6 +1319,7 @@ public class TestSaveCardsRequest 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"; } diff --git a/backend/DramaLing.Api/Models/Entities/User.cs b/backend/DramaLing.Api/Models/Entities/User.cs index d34de50..2e5353f 100644 --- a/backend/DramaLing.Api/Models/Entities/User.cs +++ b/backend/DramaLing.Api/Models/Entities/User.cs @@ -29,6 +29,16 @@ public class User public Dictionary 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; } // 程度設定備註 + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; diff --git a/backend/DramaLing.Api/Services/CEFRLevelService.cs b/backend/DramaLing.Api/Services/CEFRLevelService.cs new file mode 100644 index 0000000..3e01a5d --- /dev/null +++ b/backend/DramaLing.Api/Services/CEFRLevelService.cs @@ -0,0 +1,59 @@ +using System; + +namespace DramaLing.Api.Services; + +public static class CEFRLevelService +{ + private static readonly string[] Levels = { "A1", "A2", "B1", "B2", "C1", "C2" }; + + /// + /// 取得 CEFR 等級的數字索引 + /// + public static int GetLevelIndex(string level) + { + if (string.IsNullOrEmpty(level)) return 1; // 預設 A2 + return Array.IndexOf(Levels, level.ToUpper()); + } + + /// + /// 判定詞彙對特定用戶是否為高價值 + /// 規則:比用戶程度高 1-2 級的詞彙為高價值 + /// + 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; + } + + /// + /// 取得用戶的目標學習等級範圍 + /// + 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}"; + } + + /// + /// 取得下一個等級 + /// + 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]; + } +} \ No newline at end of file diff --git a/backend/DramaLing.Api/Services/GeminiService.cs b/backend/DramaLing.Api/Services/GeminiService.cs index 11c9ebd..1ce3041 100644 --- a/backend/DramaLing.Api/Services/GeminiService.cs +++ b/backend/DramaLing.Api/Services/GeminiService.cs @@ -8,7 +8,7 @@ public interface IGeminiService { Task> GenerateCardsAsync(string inputText, string extractionType, int cardCount); Task ValidateCardAsync(Flashcard card); - Task AnalyzeSentenceAsync(string inputText); + Task AnalyzeSentenceAsync(string inputText, string userLevel = "A2"); Task AnalyzeWordAsync(string word, string sentence); } @@ -52,7 +52,7 @@ public class GeminiService : IGeminiService /// /// 真正的句子分析和翻譯 - 調用 Gemini AI /// - public async Task AnalyzeSentenceAsync(string inputText) + public async Task AnalyzeSentenceAsync(string inputText, string userLevel = "A2") { try { @@ -61,10 +61,13 @@ public class GeminiService : IGeminiService throw new InvalidOperationException("Gemini API key not configured"); } + var targetRange = CEFRLevelService.GetTargetLevelRange(userLevel); + var prompt = $@" -請分析以下英文句子,提供翻譯和詞彙分析: +請分析以下英文句子,提供翻譯和個人化詞彙分析: 句子:{inputText} +學習者程度:{userLevel} 請按照以下JSON格式回應,不要包含任何其他文字: @@ -91,9 +94,16 @@ public class GeminiService : IGeminiService 要求: 1. 翻譯要自然流暢,符合中文語法 -2. 標記B1以上詞彙為高價值 +2. **基於學習者程度({userLevel}),標記 {targetRange} 等級的詞彙為高價值** 3. 如有語法錯誤請指出並修正 4. 確保JSON格式正確 + +高價值判定邏輯: +- 學習者程度: {userLevel} +- 高價值範圍: {targetRange} +- 太簡單的詞彙(≤{userLevel})不要標記為高價值 +- 太難的詞彙謹慎標記 +- 重點關注適合學習者程度的詞彙 "; var response = await CallGeminiApiAsync(prompt); diff --git a/frontend/app/generate/page.tsx b/frontend/app/generate/page.tsx index e18d1f3..7ee898a 100644 --- a/frontend/app/generate/page.tsx +++ b/frontend/app/generate/page.tsx @@ -5,6 +5,7 @@ import { ProtectedRoute } from '@/components/ProtectedRoute' import { Navigation } from '@/components/Navigation' import { ClickableTextV2 } from '@/components/ClickableTextV2' import { GrammarCorrectionPanel } from '@/components/GrammarCorrectionPanel' +import Link from 'next/link' function GenerateContent() { const [mode, setMode] = useState<'manual' | 'screenshot'>('manual') @@ -34,6 +35,10 @@ function GenerateContent() { return } + // 取得用戶設定的程度 + const userLevel = localStorage.getItem('userEnglishLevel') || 'A2'; + console.log('🎯 使用用戶程度:', userLevel); + if (!isPremium && usageCount >= 5) { console.log('❌ 使用次數超限') alert('❌ 免費用戶 3 小時內只能分析 5 次句子,請稍後再試或升級到付費版本') @@ -53,6 +58,7 @@ function GenerateContent() { }, body: JSON.stringify({ inputText: textInput, + userLevel: userLevel, // 傳遞用戶程度 analysisMode: 'full' }) }) @@ -292,6 +298,33 @@ function GenerateContent() { )} + + {/* 個人化程度指示器 */} +
+ {(() => { + const userLevel = localStorage.getItem('userEnglishLevel') || 'A2'; + const getTargetRange = (level: string) => { + const ranges = { + 'A1': 'A2-B1', 'A2': 'B1-B2', 'B1': 'B2-C1', + 'B2': 'C1-C2', 'C1': 'C2', 'C2': 'C2' + }; + return ranges[level as keyof typeof ranges] || 'B1-B2'; + }; + return ( +
+ 🎯 您的程度: {userLevel} + | + 💎 高價值範圍: {getTargetRange(userLevel)} + + 調整 ⚙️ + +
+ ); + })()} +
) : showAnalysisView ? ( diff --git a/frontend/app/settings/page.tsx b/frontend/app/settings/page.tsx new file mode 100644 index 0000000..bc66516 --- /dev/null +++ b/frontend/app/settings/page.tsx @@ -0,0 +1,209 @@ +'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'] + } + ]; + + // 載入用戶已設定的程度 + useEffect(() => { + const savedLevel = localStorage.getItem('userEnglishLevel'); + if (savedLevel) { + setUserLevel(savedLevel); + } + }, []); + + const saveUserLevel = async () => { + setIsLoading(true); + try { + // 保存到本地存儲 + localStorage.setItem('userEnglishLevel', userLevel); + + // TODO: 如果用戶已登入,也保存到伺服器 + // 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': 'C2', + 'C2': 'C2' + }; + return ranges[level as keyof typeof ranges] || 'B1-B2'; + }; + + return ( +
+
+

🎯 英語程度設定

+

+ 設定您的英語程度,系統將為您提供個人化的詞彙學習建議。 + 設定後,我們會重點標記比您目前程度高1-2級的詞彙。 +

+
+ +
+ {levels.map(level => ( + + ))} +
+ + {/* 個人化效果預覽 */} +
+

+ 💡 您的個人化學習效果預覽 +

+
+
+

高價值詞彙範圍

+

+ 系統將重點標記 {getHighValueRange(userLevel)} 等級的詞彙 +

+
+
+

學習建議

+

+ 專注於比您目前程度({userLevel})高1-2級的詞彙,既有挑戰性又不會太困難 +

+
+
+
+ + + +
+

+ 💡 提示: 您隨時可以回到這裡調整程度設定 +

+
+
+ ); +} \ No newline at end of file diff --git a/frontend/components/Navigation.tsx b/frontend/components/Navigation.tsx index e6b8a5f..87cd0fe 100644 --- a/frontend/components/Navigation.tsx +++ b/frontend/components/Navigation.tsx @@ -19,7 +19,8 @@ export function Navigation({ showExitLearning = false, onExitLearning }: Navigat { href: '/dashboard', label: '儀表板' }, { href: '/flashcards', label: '詞卡' }, { href: '/learn', label: '學習' }, - { href: '/generate', label: 'AI 生成' } + { href: '/generate', label: 'AI 生成' }, + { href: '/settings', label: '⚙️ 設定' } ] return (