docs: 完成AI詞彙分析系統規格文件並整合個人化重點學習範圍
📋 文件內容: - 創建完整的AI詞彙分析生成系統規格文件 - 整合個人化重點學習範圍系統設計 - 詳細的功能規格、技術架構、API規格 🎯 重大概念更新: - 高價值詞彙 → 重點學習範圍概念 - AI不再自己決定,改由CEFRLevelService判定 - 個人化判定邏輯:用戶程度+1~2階級 🔧 前端修正: - 修正getWordProperty函數處理AI資料格式不完整問題 - 智能處理同義詞、例句等缺失欄位 - 前端能夠適應AI回應格式變化 🏗️ 後端詞彙庫擴充: - 新增用戶例句中的所有詞彙翻譯和定義 - 修正同義詞函數返回空數組而非無意義文字 - 確保AI分析和本地增強的整合 📊 規格文件特色: - v2.0版本整合個人化系統 - 完整的CEFR等級判定邏輯 - Portal設計技術規格 - 用戶程度設定系統架構 - 個人化快取策略 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b348780eaa
commit
a5c439bbaf
|
|
@ -0,0 +1,905 @@
|
|||
# AI詞彙分析生成系統規格
|
||||
|
||||
## 📋 **系統概述**
|
||||
|
||||
DramaLing 的 AI 詞彙分析生成系統是一個完整的英語學習輔助工具,提供智能句子分析、詞彙詳細解釋、語法修正建議,以及個人化的詞卡儲存功能。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **功能規格**
|
||||
|
||||
### 1. **句子分析功能**
|
||||
|
||||
#### 1.1 核心功能
|
||||
- **智能句子解析**: 使用 Gemini AI 分析英文句子結構和語義
|
||||
- **語法錯誤檢測**: 自動檢測並提供語法修正建議
|
||||
- **中文翻譯生成**: 提供自然流暢的中文翻譯
|
||||
- **重點學習範圍標記**: 根據用戶CEFR等級智能標記重點學習詞彙(用戶程度+1~2階級)
|
||||
|
||||
#### 1.2 輸入限制
|
||||
- **手動輸入**: 最大300字符
|
||||
- **截圖輸入**: 支援圖片OCR識別(預留功能)
|
||||
- **語言檢測**: 自動檢測英文內容
|
||||
|
||||
#### 1.3 輸出內容
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"analysisId": "guid",
|
||||
"inputText": "原始輸入文本",
|
||||
"userLevel": "A2|B1|B2|C1|C2",
|
||||
"highValueCriteria": "B1-B2", // 用戶的重點學習範圍
|
||||
"grammarCorrection": {
|
||||
"hasErrors": boolean,
|
||||
"originalText": "string",
|
||||
"correctedText": "string|null",
|
||||
"corrections": []
|
||||
},
|
||||
"sentenceMeaning": {
|
||||
"translation": "中文翻譯"
|
||||
},
|
||||
"finalAnalysisText": "最終分析文本",
|
||||
"wordAnalysis": {
|
||||
"詞彙": {
|
||||
"word": "string",
|
||||
"translation": "中文翻譯",
|
||||
"definition": "英文定義",
|
||||
"partOfSpeech": "詞性",
|
||||
"pronunciation": "IPA音標",
|
||||
"isHighValue": boolean, // 由CEFRLevelService判定,非AI決定
|
||||
"difficultyLevel": "CEFR等級"
|
||||
}
|
||||
},
|
||||
"highValueWords": ["重點學習詞彙數組"], // 由後端邏輯決定,非AI決定
|
||||
"phrasesDetected": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **可點擊詞彙功能**
|
||||
|
||||
#### 2.1 詞彙互動
|
||||
- **即時彈窗**: 點擊任意詞彙顯示詳細資訊
|
||||
- **智能定位**: 彈窗自動避開屏幕邊界
|
||||
- **響應式設計**: 適配桌面端和移動端
|
||||
|
||||
#### 2.2 個人化詞彙分類標記
|
||||
根據用戶CEFR等級進行個人化標記:
|
||||
|
||||
| 用戶程度 | 重點學習範圍 | 標記詞彙 | 視覺效果 |
|
||||
|----------|--------------|----------|----------|
|
||||
| **A1** | A2-B1 | A2, B1 詞彙 | 綠色邊框 + ⭐ |
|
||||
| **A2** | B1-B2 | B1, B2 詞彙 | 綠色邊框 + ⭐ |
|
||||
| **B1** | B2-C1 | B2, C1 詞彙 | 綠色邊框 + ⭐ |
|
||||
| **B2** | C1-C2 | C1, C2 詞彙 | 綠色邊框 + ⭐ |
|
||||
| **C1** | C1-C2 | C1, C2 詞彙 | 綠色邊框 + ⭐ |
|
||||
|
||||
- **重點學習詞彙**: 綠色邊框 + ⭐ 標記(用戶程度+1~2階級)
|
||||
- **重點學習片語**: 黃色邊框 + ⭐ 標記
|
||||
- **普通詞彙**: 藍色邊框(已掌握或太難的詞彙)
|
||||
- **未分析詞彙**: 灰色虛線邊框
|
||||
|
||||
#### 2.3 詞彙詳情彈窗
|
||||
採用**詞卡風格設計**,包含:
|
||||
- **標題區**: 漸層背景,詞彙名稱 + CEFR等級標籤
|
||||
- **基本資訊**: 詞性標籤、IPA發音、播放按鈕
|
||||
- **翻譯區塊**: 綠色背景,中文翻譯
|
||||
- **定義區塊**: 灰色背景,英文定義
|
||||
- **同義詞區塊**: 紫色背景,相關同義詞
|
||||
- **儲存按鈕**: 一鍵保存到個人詞卡庫
|
||||
|
||||
### 3. **詞卡儲存系統**
|
||||
|
||||
#### 3.1 儲存功能
|
||||
- **一鍵儲存**: 從詞彙彈窗直接保存到詞卡
|
||||
- **自動分類**: 自動加入預設詞卡組
|
||||
- **去重處理**: 避免重複儲存相同詞彙
|
||||
- **即時反饋**: 儲存成功/失敗的視覺提示
|
||||
|
||||
#### 3.2 資料結構
|
||||
```json
|
||||
{
|
||||
"word": "詞彙",
|
||||
"translation": "中文翻譯",
|
||||
"definition": "英文定義",
|
||||
"pronunciation": "IPA發音",
|
||||
"partOfSpeech": "詞性",
|
||||
"example": "例句"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. **個人化程度設定系統**
|
||||
|
||||
#### 4.1 用戶程度管理
|
||||
- **CEFR等級選擇**: A1-C2六個等級選擇
|
||||
- **本地儲存**: localStorage保存,未登入用戶也可使用
|
||||
- **雲端同步**: 登入用戶的程度設定同步到後端
|
||||
- **智能預設**: 未設定用戶預設為A2等級
|
||||
|
||||
#### 4.2 重點學習範圍邏輯
|
||||
```typescript
|
||||
// 個人化判定規則
|
||||
const getTargetLevelRange = (userLevel: string): string => {
|
||||
const ranges = {
|
||||
'A1': 'A2-B1', // A1用戶重點學習A2和B1詞彙
|
||||
'A2': 'B1-B2', // A2用戶重點學習B1和B2詞彙
|
||||
'B1': 'B2-C1', // B1用戶重點學習B2和C1詞彙
|
||||
'B2': 'C1-C2', // B2用戶重點學習C1和C2詞彙
|
||||
'C1': 'C1-C2', // C1用戶重點學習C1和C2詞彙
|
||||
'C2': 'C1-C2' // C2用戶維持高階詞彙
|
||||
};
|
||||
return ranges[userLevel] || 'B1-B2';
|
||||
};
|
||||
```
|
||||
|
||||
#### 4.3 視覺化學習指導
|
||||
- **程度指示器**: 顯示當前程度和重點學習範圍
|
||||
- **學習建議**: 基於程度提供個人化學習策略
|
||||
- **進度追蹤**: 詞彙掌握程度可視化
|
||||
|
||||
### 5. **快取系統**
|
||||
|
||||
#### 5.1 個人化快取
|
||||
- **基於用戶程度快取**: 不同程度用戶的分析結果分別快取
|
||||
- **快取鍵格式**: `{sentence}_{userLevel}` 確保個人化結果
|
||||
- **詞彙分析快取**: 高頻詞彙結果快取
|
||||
- **快取過期**: 自動清理過期項目
|
||||
|
||||
#### 5.2 效能優化
|
||||
- **智能快取策略**: 優先快取重點學習範圍的分析結果
|
||||
- **快取統計**: 提供快取命中率監控
|
||||
- **定期清理**: 自動清理過期快取項目
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **個人化重點學習範圍系統**
|
||||
|
||||
### 1. **核心設計理念**
|
||||
|
||||
#### 1.1 問題解決
|
||||
**現有問題**:
|
||||
- A1學習者看不到A2詞彙的學習價值(對他們很重要)
|
||||
- C1學習者被B1詞彙干擾(對他們太簡單)
|
||||
- 一刀切設計不符合個別學習需求
|
||||
|
||||
**解決方案**:
|
||||
```
|
||||
新邏輯:重點學習詞彙 = 用戶當前程度 + 1~2階級
|
||||
```
|
||||
|
||||
#### 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,C2** | 專注高階詞彙 |
|
||||
| **C1** | B1,B2,C1,C2 | **C1,C2** | 專注高階詞彙精進 |
|
||||
|
||||
### 2. **技術實現架構**
|
||||
|
||||
#### 2.1 CEFRLevelService
|
||||
```csharp
|
||||
public static class CEFRLevelService
|
||||
{
|
||||
// 判定詞彙對特定用戶是否為重點學習
|
||||
public static bool IsHighValueForUser(string wordLevel, string userLevel)
|
||||
{
|
||||
var userIndex = GetLevelIndex(userLevel);
|
||||
var wordIndex = GetLevelIndex(wordLevel);
|
||||
|
||||
// 重點學習範圍:比用戶程度高 1-2 級
|
||||
return wordIndex >= userIndex + 1 && wordIndex <= userIndex + 2;
|
||||
}
|
||||
|
||||
// 取得用戶的目標學習等級範圍
|
||||
public static string GetTargetLevelRange(string userLevel)
|
||||
{
|
||||
var userIndex = GetLevelIndex(userLevel);
|
||||
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}";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 AI Prompt個人化
|
||||
```csharp
|
||||
// Gemini AI Prompt 動態生成
|
||||
private string BuildSentenceAnalysisPrompt(string inputText, string userLevel)
|
||||
{
|
||||
var targetRange = CEFRLevelService.GetTargetLevelRange(userLevel);
|
||||
|
||||
return $@"
|
||||
請分析以下英文句子:{inputText}
|
||||
學習者程度:{userLevel}
|
||||
|
||||
要求:
|
||||
1. 提供自然流暢的繁體中文翻譯
|
||||
2. **基於學習者程度({userLevel}),標記 {targetRange} 等級的詞彙為高價值**
|
||||
3. 太簡單的詞彙(≤{userLevel})不要標記為高價值
|
||||
4. 太難的詞彙(>{targetRange})謹慎標記
|
||||
|
||||
高價值判定邏輯:
|
||||
- 重點關注 {targetRange} 範圍內的詞彙
|
||||
- 提供適合當前程度的學習挑戰
|
||||
";
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 後處理驗證
|
||||
```csharp
|
||||
// AI結果的後處理驗證
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **用戶程度設定介面**
|
||||
|
||||
#### 3.1 設定頁面設計
|
||||
- **等級選擇器**: 6個CEFR等級的圖形化選擇
|
||||
- **程度描述**: 每個等級的能力描述和範例詞彙
|
||||
- **效果預覽**: 顯示選擇該程度的重點學習範圍
|
||||
- **學習建議**: 基於程度的個人化學習策略
|
||||
|
||||
#### 3.2 整合到分析流程
|
||||
```typescript
|
||||
// 前端API調用整合
|
||||
const handleAnalyzeSentence = async () => {
|
||||
const userLevel = localStorage.getItem('userEnglishLevel') || 'A2';
|
||||
|
||||
const response = await fetch('/api/ai/analyze-sentence', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
inputText: textInput,
|
||||
userLevel: userLevel, // 傳遞用戶程度
|
||||
analysisMode: 'full'
|
||||
})
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ **技術架構**
|
||||
|
||||
### 1. **前端架構 (Next.js + TypeScript)**
|
||||
|
||||
#### 1.1 核心組件
|
||||
```typescript
|
||||
// 主要組件
|
||||
ClickableTextV2.tsx // 可點擊文本組件(使用React Portal)
|
||||
GeneratePage.tsx // 句子分析主頁面
|
||||
FlashcardsPage.tsx // 詞卡管理頁面
|
||||
|
||||
// 輔助組件
|
||||
Navigation.tsx // 導航組件
|
||||
ProtectedRoute.tsx // 路由保護
|
||||
```
|
||||
|
||||
#### 1.2 狀態管理
|
||||
```typescript
|
||||
// 分析狀態
|
||||
const [sentenceAnalysis, setSentenceAnalysis] = useState<Record<string, WordAnalysis>>({})
|
||||
const [sentenceMeaning, setSentenceMeaning] = useState<string>('')
|
||||
const [grammarCorrection, setGrammarCorrection] = useState<GrammarCorrection | null>(null)
|
||||
|
||||
// UI狀態
|
||||
const [selectedWord, setSelectedWord] = useState<string | null>(null)
|
||||
const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0, showBelow: false })
|
||||
const [isSavingWord, setIsSavingWord] = useState<boolean>(false)
|
||||
```
|
||||
|
||||
#### 1.3 API服務層
|
||||
```typescript
|
||||
// 服務介面
|
||||
flashcardsService.createFlashcard() // 詞卡創建
|
||||
flashcardsService.getFlashcards() // 詞卡查詢
|
||||
flashcardsService.deleteFlashcard() // 詞卡刪除
|
||||
|
||||
// API端點
|
||||
POST /api/ai/analyze-sentence // 句子分析
|
||||
POST /api/flashcards // 詞卡創建
|
||||
GET /api/flashcards // 詞卡查詢
|
||||
```
|
||||
|
||||
### 2. **後端架構 (.NET 8 + Entity Framework)**
|
||||
|
||||
#### 2.1 控制器層
|
||||
```csharp
|
||||
AIController.cs // AI分析相關API
|
||||
FlashcardsController.cs // 詞卡CRUD操作
|
||||
AuthController.cs // 用戶認證
|
||||
StatsController.cs // 統計資料
|
||||
```
|
||||
|
||||
#### 2.2 服務層
|
||||
```csharp
|
||||
GeminiService.cs // Gemini AI整合
|
||||
AudioCacheService.cs // 音頻快取管理
|
||||
AuthService.cs // 認證服務
|
||||
CacheCleanupService.cs // 快取清理服務
|
||||
```
|
||||
|
||||
#### 2.3 資料層
|
||||
```csharp
|
||||
// 主要實體
|
||||
User.cs // 用戶資料
|
||||
Flashcard.cs // 詞卡實體
|
||||
CardSet.cs // 詞卡組
|
||||
SentenceAnalysisCache.cs // 分析快取
|
||||
|
||||
// 資料庫上下文
|
||||
DramaLingDbContext.cs // EF DbContext
|
||||
```
|
||||
|
||||
### 3. **資料庫設計 (SQLite)**
|
||||
|
||||
#### 3.1 核心表結構
|
||||
```sql
|
||||
-- 詞卡表
|
||||
Flashcards {
|
||||
Id: GUID (PK)
|
||||
UserId: GUID (FK)
|
||||
CardSetId: GUID (FK)
|
||||
Word: VARCHAR(100)
|
||||
Translation: VARCHAR(200)
|
||||
Definition: TEXT
|
||||
PartOfSpeech: VARCHAR(50)
|
||||
Pronunciation: VARCHAR(100)
|
||||
Example: TEXT
|
||||
MasteryLevel: INT
|
||||
CreatedAt: DATETIME
|
||||
}
|
||||
|
||||
-- 分析快取表
|
||||
SentenceAnalysisCache {
|
||||
Id: GUID (PK)
|
||||
InputTextHash: VARCHAR(64) (Index)
|
||||
AnalysisResult: TEXT
|
||||
ExpiresAt: DATETIME (Index)
|
||||
AccessCount: INT
|
||||
CreatedAt: DATETIME
|
||||
}
|
||||
```
|
||||
|
||||
### 4. **AI整合架構**
|
||||
|
||||
#### 4.1 Gemini AI整合
|
||||
```csharp
|
||||
// AI分析流程
|
||||
1. 接收用戶輸入 →
|
||||
2. 檢查快取 →
|
||||
3. 調用Gemini API →
|
||||
4. 解析AI回應 →
|
||||
5. 補充本地資料 →
|
||||
6. 儲存快取 →
|
||||
7. 返回結果
|
||||
```
|
||||
|
||||
#### 4.2 回退機制
|
||||
```csharp
|
||||
// AI失敗處理
|
||||
try {
|
||||
// Gemini AI分析
|
||||
} catch {
|
||||
// 回退到本地分析
|
||||
return LocalAnalysis();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **API規格**
|
||||
|
||||
### 1. **句子分析API**
|
||||
|
||||
#### 端點
|
||||
```
|
||||
POST /api/ai/analyze-sentence
|
||||
```
|
||||
|
||||
#### 請求格式
|
||||
```json
|
||||
{
|
||||
"inputText": "要分析的英文句子",
|
||||
"userLevel": "A2", // 用戶CEFR等級,用於個人化重點學習範圍判定
|
||||
"analysisMode": "full"
|
||||
}
|
||||
```
|
||||
|
||||
#### 回應格式
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"analysisId": "830ef2a1-83fd-4cfd-ae74-7b54350bff5e",
|
||||
"inputText": "The company offered a bonus",
|
||||
"userLevel": "A2",
|
||||
"highValueCriteria": "B1-B2", // A2用戶的重點學習範圍
|
||||
"grammarCorrection": {
|
||||
"hasErrors": false,
|
||||
"originalText": "The company offered a bonus",
|
||||
"correctedText": "",
|
||||
"corrections": []
|
||||
},
|
||||
"sentenceMeaning": {
|
||||
"translation": "公司發放了獎金。"
|
||||
},
|
||||
"finalAnalysisText": "The company offered a bonus",
|
||||
"wordAnalysis": {
|
||||
"bonus": {
|
||||
"word": "bonus",
|
||||
"translation": "獎金",
|
||||
"definition": "An extra amount of money added to a person's salary",
|
||||
"partOfSpeech": "Noun",
|
||||
"pronunciation": "/ˈbəʊnəs/",
|
||||
"isHighValue": true, // 由CEFRLevelService判定:B1屬於A2用戶的重點學習範圍
|
||||
"difficultyLevel": "B1"
|
||||
}
|
||||
},
|
||||
"highValueWords": ["offered", "bonus"], // 由CEFRLevelService判定,非AI決定
|
||||
"phrasesDetected": []
|
||||
},
|
||||
"message": "AI句子分析完成",
|
||||
"usingAI": true
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **詞卡儲存API**
|
||||
|
||||
#### 端點
|
||||
```
|
||||
POST /api/flashcards
|
||||
```
|
||||
|
||||
#### 請求格式
|
||||
```json
|
||||
{
|
||||
"word": "bonus",
|
||||
"translation": "獎金、紅利",
|
||||
"definition": "An extra payment given in addition to regular salary",
|
||||
"pronunciation": "/ˈboʊnəs/",
|
||||
"partOfSpeech": "noun",
|
||||
"example": "I received a Christmas bonus this year."
|
||||
}
|
||||
```
|
||||
|
||||
#### 回應格式
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "flashcard-id",
|
||||
"word": "bonus",
|
||||
"translation": "獎金、紅利",
|
||||
"cardSet": {
|
||||
"name": "未分類",
|
||||
"color": "bg-slate-700"
|
||||
}
|
||||
},
|
||||
"message": "詞卡創建成功"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 **UI/UX設計規格**
|
||||
|
||||
### 1. **Portal彈窗設計**
|
||||
|
||||
#### 1.1 設計原則
|
||||
- **詞卡風格一致性**: 與展示頁面的詞卡風格100%一致
|
||||
- **CSS隔離**: 使用React Portal避免樣式繼承問題
|
||||
- **響應式設計**: 適配各種屏幕尺寸
|
||||
|
||||
#### 1.2 視覺規格
|
||||
```css
|
||||
/* 彈窗容器 */
|
||||
.popup-container {
|
||||
width: 24rem; /* w-96 */
|
||||
max-width: 28rem; /* max-w-md */
|
||||
border-radius: 0.75rem; /* rounded-xl */
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); /* shadow-lg */
|
||||
}
|
||||
|
||||
/* 標題區漸層 */
|
||||
.title-section {
|
||||
background: linear-gradient(to bottom right, #dbeafe, #e0e7ff); /* from-blue-50 to-indigo-50 */
|
||||
padding: 1.25rem; /* p-5 */
|
||||
border-bottom: 1px solid #c3ddfd; /* border-blue-200 */
|
||||
}
|
||||
|
||||
/* CEFR顏色系統 */
|
||||
.cefr-a1 { background: #dcfce7; color: #166534; border: #bbf7d0; } /* 綠色 */
|
||||
.cefr-a2 { background: #dbeafe; color: #1e40af; border: #bfdbfe; } /* 藍色 */
|
||||
.cefr-b1 { background: #fef3c7; color: #a16207; border: #fde68a; } /* 黃色 */
|
||||
.cefr-b2 { background: #fed7aa; color: #c2410c; border: #fdba74; } /* 橙色 */
|
||||
.cefr-c1 { background: #fecaca; color: #dc2626; border: #fca5a5; } /* 紅色 */
|
||||
.cefr-c2 { background: #e9d5ff; color: #7c3aed; border: #c4b5fd; } /* 紫色 */
|
||||
```
|
||||
|
||||
### 2. **彩色區塊設計**
|
||||
|
||||
#### 2.1 內容區塊
|
||||
- **翻譯區塊**: 綠色系 (`bg-green-50`, `border-green-200`)
|
||||
- **定義區塊**: 灰色系 (`bg-gray-50`, `border-gray-200`)
|
||||
- **同義詞區塊**: 紫色系 (`bg-purple-50`, `border-purple-200`)
|
||||
|
||||
#### 2.2 互動元素
|
||||
- **播放按鈕**: 藍色圓形 (`bg-blue-600`, `w-8 h-8`)
|
||||
- **儲存按鈕**: 主色調 (`bg-primary`, `hover:bg-primary-hover`)
|
||||
- **關閉按鈕**: 半透明白色 (`bg-white bg-opacity-80`)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **技術實現規格**
|
||||
|
||||
### 1. **前端技術棧**
|
||||
|
||||
#### 1.1 核心技術
|
||||
```json
|
||||
{
|
||||
"framework": "Next.js 15.5.3",
|
||||
"language": "TypeScript",
|
||||
"styling": "Tailwind CSS",
|
||||
"stateManagement": "React Hooks",
|
||||
"apiClient": "Fetch API"
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 關鍵實現
|
||||
```typescript
|
||||
// React Portal實現
|
||||
const VocabPopup = () => {
|
||||
if (!selectedWord || !analysis?.[selectedWord] || !mounted) return null
|
||||
|
||||
return createPortal(
|
||||
<div className="fixed z-50 bg-white rounded-xl shadow-lg w-96 max-w-md overflow-hidden">
|
||||
{/* 彈窗內容 */}
|
||||
</div>,
|
||||
document.body
|
||||
)
|
||||
}
|
||||
|
||||
// 智能屬性讀取
|
||||
const getWordProperty = (wordData: any, propName: string) => {
|
||||
// 處理大小寫不一致
|
||||
const lowerProp = propName.toLowerCase()
|
||||
const upperProp = propName.charAt(0).toUpperCase() + propName.slice(1)
|
||||
|
||||
// 特殊處理AI資料缺失
|
||||
if (propName === 'synonyms') {
|
||||
return wordData?.[lowerProp] || wordData?.[upperProp] || []
|
||||
}
|
||||
|
||||
return wordData?.[lowerProp] || wordData?.[upperProp]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **後端技術棧**
|
||||
|
||||
#### 2.1 核心技術
|
||||
```json
|
||||
{
|
||||
"framework": ".NET 8.0",
|
||||
"language": "C#",
|
||||
"database": "SQLite + Entity Framework Core",
|
||||
"ai": "Google Gemini API",
|
||||
"authentication": "JWT Bearer Token"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 關鍵實現
|
||||
```csharp
|
||||
// AI分析服務 - 整合個人化重點學習範圍
|
||||
[HttpPost("analyze-sentence")]
|
||||
public async Task<ActionResult> AnalyzeSentence([FromBody] AnalyzeSentenceRequest request)
|
||||
{
|
||||
// 1. 取得用戶程度
|
||||
string userLevel = request.UserLevel ?? await GetUserLevelFromAuth() ?? "A2";
|
||||
|
||||
// 2. 快取檢查(基於用戶程度)
|
||||
var cacheKey = $"{request.InputText}_{userLevel}";
|
||||
var cachedResult = await CheckCache(cacheKey);
|
||||
if (cachedResult != null) return Ok(cachedResult);
|
||||
|
||||
// 3. AI分析(傳遞用戶程度)
|
||||
var aiAnalysis = await _geminiService.AnalyzeSentenceAsync(request.InputText, userLevel);
|
||||
|
||||
// 4. 重點學習範圍判定(關鍵步驟)
|
||||
var enhancedAnalysis = PostProcessHighValueWords(aiAnalysis, userLevel);
|
||||
|
||||
// 5. 快取儲存
|
||||
await SaveToCache(cacheKey, enhancedAnalysis);
|
||||
|
||||
return Ok(new {
|
||||
Success = true,
|
||||
Data = new {
|
||||
AnalysisId = Guid.NewGuid(),
|
||||
InputText = request.InputText,
|
||||
UserLevel = userLevel,
|
||||
HighValueCriteria = CEFRLevelService.GetTargetLevelRange(userLevel),
|
||||
GrammarCorrection = enhancedAnalysis.GrammarCorrection,
|
||||
SentenceMeaning = new { Translation = enhancedAnalysis.Translation },
|
||||
FinalAnalysisText = request.InputText,
|
||||
WordAnalysis = enhancedAnalysis.WordAnalysis,
|
||||
HighValueWords = enhancedAnalysis.HighValueWords
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重點學習範圍判定服務
|
||||
public static class CEFRLevelService
|
||||
{
|
||||
public static bool IsHighValueForUser(string wordLevel, string userLevel)
|
||||
{
|
||||
var userIndex = GetLevelIndex(userLevel);
|
||||
var wordIndex = GetLevelIndex(wordLevel);
|
||||
|
||||
// 重點學習範圍:用戶程度 + 1~2 階級
|
||||
return wordIndex >= userIndex + 1 && wordIndex <= userIndex + 2;
|
||||
}
|
||||
|
||||
public static string GetTargetLevelRange(string userLevel)
|
||||
{
|
||||
var levels = new[] { "A1", "A2", "B1", "B2", "C1", "C2" };
|
||||
var userIndex = Array.IndexOf(levels, userLevel);
|
||||
|
||||
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}";
|
||||
}
|
||||
}
|
||||
|
||||
// 詞彙分析增強
|
||||
private Dictionary<string, object> GenerateWordAnalysisForSentence(string text)
|
||||
{
|
||||
var analysis = new Dictionary<string, object>();
|
||||
var words = text.Split(new[] { ' ', '.', ',', '!', '?' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var word in words)
|
||||
{
|
||||
analysis[word] = new
|
||||
{
|
||||
word = word,
|
||||
translation = GetWordTranslation(word),
|
||||
definition = GetWordDefinition(word),
|
||||
partOfSpeech = GetPartOfSpeech(word),
|
||||
pronunciation = GetPronunciation(word),
|
||||
synonyms = GetSynonyms(word),
|
||||
isHighValue = IsHighValueWord(word),
|
||||
difficultyLevel = GetWordDifficulty(word)
|
||||
};
|
||||
}
|
||||
|
||||
return analysis;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **資料庫架構**
|
||||
|
||||
#### 3.1 實體關係
|
||||
```
|
||||
User (1) ←→ (N) CardSet (1) ←→ (N) Flashcard
|
||||
User (1) ←→ (N) SentenceAnalysisCache
|
||||
User (1) ←→ (N) WordQueryUsageStats
|
||||
```
|
||||
|
||||
#### 3.2 索引策略
|
||||
```sql
|
||||
-- 效能索引
|
||||
CREATE INDEX IX_SentenceAnalysisCache_InputTextHash ON SentenceAnalysisCache(InputTextHash);
|
||||
CREATE INDEX IX_SentenceAnalysisCache_ExpiresAt ON SentenceAnalysisCache(ExpiresAt);
|
||||
CREATE INDEX IX_Flashcards_UserId_Word ON Flashcards(UserId, Word);
|
||||
CREATE INDEX IX_WordQueryUsageStats_UserId_Date ON WordQueryUsageStats(UserId, Date);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 **效能與擴展規格**
|
||||
|
||||
### 1. **效能指標**
|
||||
|
||||
#### 1.1 回應時間
|
||||
- **快取命中**: < 100ms
|
||||
- **AI分析**: < 3000ms
|
||||
- **詞卡儲存**: < 500ms
|
||||
- **彈窗顯示**: < 50ms
|
||||
|
||||
#### 1.2 併發處理
|
||||
- **最大併發用戶**: 100
|
||||
- **AI API限制**: 每分鐘60次請求
|
||||
- **資料庫連線池**: 20個連線
|
||||
|
||||
### 2. **擴展性設計**
|
||||
|
||||
#### 2.1 水平擴展
|
||||
- **無狀態設計**: 所有狀態存於資料庫
|
||||
- **API分離**: 前後端完全分離
|
||||
- **快取策略**: 支援Redis擴展
|
||||
|
||||
#### 2.2 功能擴展
|
||||
- **多語言支援**: 預留i18n架構
|
||||
- **AI模型切換**: 支援多種AI服務
|
||||
- **音頻功能**: TTS語音合成擴展
|
||||
|
||||
---
|
||||
|
||||
## 🔒 **安全性規格**
|
||||
|
||||
### 1. **身份驗證**
|
||||
- **JWT Token**: 用戶身份驗證
|
||||
- **Token過期**: 24小時自動過期
|
||||
- **保護路由**: 所有敏感API需要認證
|
||||
|
||||
### 2. **資料安全**
|
||||
- **輸入驗證**: 防止SQL注入和XSS
|
||||
- **資料加密**: 敏感資料庫內加密
|
||||
- **CORS設定**: 限制跨域請求來源
|
||||
|
||||
### 3. **API安全**
|
||||
```csharp
|
||||
[Authorize] // 需要認證
|
||||
[ValidateAntiForgeryToken] // CSRF保護
|
||||
[Rate限制] // API調用頻率限制
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 **監控與維護**
|
||||
|
||||
### 1. **日誌系統**
|
||||
- **結構化日誌**: 使用Serilog記錄
|
||||
- **分級記錄**: Debug/Info/Warning/Error
|
||||
- **效能監控**: API回應時間追蹤
|
||||
|
||||
### 2. **健康檢查**
|
||||
```
|
||||
GET /health // 系統健康狀態
|
||||
GET /api/ai/cache-stats // 快取統計資料
|
||||
GET /api/stats/usage // 使用統計資料
|
||||
```
|
||||
|
||||
### 3. **錯誤處理**
|
||||
- **全域例外處理**: 統一錯誤回應格式
|
||||
- **使用者友善訊息**: 技術錯誤轉換為用戶可理解訊息
|
||||
- **錯誤報告**: 自動記錄並分析系統錯誤
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **部署規格**
|
||||
|
||||
### 1. **環境配置**
|
||||
```json
|
||||
{
|
||||
"development": {
|
||||
"frontend": "http://localhost:3001",
|
||||
"backend": "http://localhost:5000",
|
||||
"database": "SQLite本地檔案"
|
||||
},
|
||||
"production": {
|
||||
"frontend": "Vercel/Netlify",
|
||||
"backend": "Azure App Service",
|
||||
"database": "Azure SQL Database"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **環境變數**
|
||||
```bash
|
||||
# AI設定
|
||||
GEMINI_API_KEY=your_gemini_api_key
|
||||
|
||||
# 資料庫
|
||||
CONNECTION_STRING=Data Source=dramaling.db
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=your_jwt_secret
|
||||
JWT_ISSUER=DramaLing.Api
|
||||
JWT_AUDIENCE=DramaLing.Frontend
|
||||
|
||||
# CORS
|
||||
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 **開發與測試規格**
|
||||
|
||||
### 1. **開發環境設置**
|
||||
```bash
|
||||
# 前端
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
|
||||
# 後端
|
||||
cd backend/DramaLing.Api
|
||||
dotnet restore
|
||||
dotnet run
|
||||
```
|
||||
|
||||
### 2. **測試策略**
|
||||
- **單元測試**: 核心業務邏輯測試
|
||||
- **整合測試**: API端點測試
|
||||
- **端到端測試**: 完整用戶流程測試
|
||||
- **效能測試**: API回應時間測試
|
||||
|
||||
### 3. **品質保證**
|
||||
```typescript
|
||||
// TypeScript嚴格模式
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true
|
||||
|
||||
// ESLint規則
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": "warn"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 **使用統計與分析**
|
||||
|
||||
### 1. **用戶行為追蹤**
|
||||
- **分析次數**: 每日句子分析統計
|
||||
- **詞彙點擊**: 高頻詞彙使用統計
|
||||
- **儲存行為**: 詞卡儲存成功率
|
||||
- **學習進度**: 用戶學習軌跡分析
|
||||
|
||||
### 2. **系統效能監控**
|
||||
- **API回應時間**: 分析各端點效能
|
||||
- **快取命中率**: 優化快取策略
|
||||
- **錯誤率統計**: 監控系統穩定性
|
||||
- **AI使用量**: 追蹤AI API調用成本
|
||||
|
||||
---
|
||||
|
||||
## 🔮 **未來擴展計劃**
|
||||
|
||||
### 1. **功能擴展**
|
||||
- **語音輸入**: 支援語音轉文字
|
||||
- **文法練習**: 基於分析結果生成練習題
|
||||
- **學習路徑**: 個人化學習建議
|
||||
- **社群功能**: 詞卡分享與協作
|
||||
|
||||
### 2. **技術優化**
|
||||
- **AI模型升級**: 整合更先進的語言模型
|
||||
- **快取優化**: 引入Redis提升效能
|
||||
- **微服務架構**: 將功能模組化部署
|
||||
- **實時同步**: WebSocket即時更新
|
||||
|
||||
---
|
||||
|
||||
**文件版本**: v2.0 (整合個人化重點學習範圍系統)
|
||||
**建立日期**: 2025-09-21
|
||||
**最後更新**: 2025-09-21
|
||||
**重大更新**:
|
||||
- 高價值詞彙 → 重點學習範圍概念
|
||||
- 個人化CEFR等級判定邏輯
|
||||
- CEFRLevelService技術架構
|
||||
- 用戶程度設定系統整合
|
||||
|
||||
**維護團隊**: DramaLing開發團隊
|
||||
|
|
@ -1146,6 +1146,14 @@ public class AIController : ControllerBase
|
|||
"since" => "因為、自從",
|
||||
"he" => "他",
|
||||
"is" => "是",
|
||||
"company" => "公司",
|
||||
"offered" => "提供了",
|
||||
"bonus" => "獎金、紅利",
|
||||
"employees" => "員工",
|
||||
"wanted" => "想要",
|
||||
"even" => "甚至",
|
||||
"more" => "更多",
|
||||
"benefits" => "福利、好處",
|
||||
"new" => "新的",
|
||||
"job" => "工作",
|
||||
"think" => "認為",
|
||||
|
|
@ -1177,6 +1185,12 @@ public class AIController : ControllerBase
|
|||
{
|
||||
return word.ToLower() switch
|
||||
{
|
||||
"company" => "A commercial business organization",
|
||||
"offered" => "Past tense of offer; to present something for acceptance",
|
||||
"bonus" => "An extra payment given in addition to regular salary",
|
||||
"employees" => "People who work for a company or organization",
|
||||
"wanted" => "Past tense of want; to desire or wish for something",
|
||||
"benefits" => "Advantages or helpful features provided by an employer",
|
||||
"animals" => "Living creatures that can move and feel",
|
||||
"instincts" => "Natural behavior that animals are born with",
|
||||
"safe" => "Not in danger; protected from harm",
|
||||
|
|
@ -1193,6 +1207,12 @@ public class AIController : ControllerBase
|
|||
{
|
||||
return word.ToLower() switch
|
||||
{
|
||||
"company" => "noun",
|
||||
"offered" => "verb",
|
||||
"bonus" => "noun",
|
||||
"employees" => "noun",
|
||||
"wanted" => "verb",
|
||||
"benefits" => "noun",
|
||||
"animals" => "noun",
|
||||
"use" => "verb",
|
||||
"their" => "pronoun",
|
||||
|
|
@ -1213,12 +1233,21 @@ public class AIController : ControllerBase
|
|||
{
|
||||
return word.ToLower() switch
|
||||
{
|
||||
// 你的例句詞彙
|
||||
"company" => new[] { "business", "corporation", "firm" },
|
||||
"offered" => new[] { "provided", "gave", "presented" },
|
||||
"bonus" => new[] { "reward", "incentive", "extra pay" },
|
||||
"employees" => new[] { "workers", "staff", "personnel" },
|
||||
"wanted" => new[] { "desired", "wished for", "sought" },
|
||||
"benefits" => new[] { "advantages", "perks", "rewards" },
|
||||
|
||||
// 原有詞彙
|
||||
"animals" => new[] { "creatures", "beings" },
|
||||
"instincts" => new[] { "intuition", "impulse" },
|
||||
"safe" => new[] { "secure", "protected" },
|
||||
"food" => new[] { "nourishment", "sustenance" },
|
||||
"find" => new[] { "locate", "discover" },
|
||||
_ => new[] { "synonym1", "synonym2" }
|
||||
_ => new string[0] // 返回空數組而不是無意義的文字
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1229,6 +1258,12 @@ public class AIController : ControllerBase
|
|||
{
|
||||
return word.ToLower() switch
|
||||
{
|
||||
"company" => "A2",
|
||||
"offered" => "B1",
|
||||
"bonus" => "B2",
|
||||
"employees" => "B1",
|
||||
"wanted" => "A1",
|
||||
"benefits" => "B2",
|
||||
"animals" => "A2",
|
||||
"instincts" => "B2",
|
||||
"safe" => "A1",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ function GenerateContent() {
|
|||
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
text: textInput
|
||||
inputText: textInput
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -49,10 +49,10 @@ function GenerateContent() {
|
|||
console.log('✅ API分析完成:', result)
|
||||
|
||||
if (result.success) {
|
||||
setSentenceAnalysis(result.data.wordAnalysis || {})
|
||||
setSentenceMeaning(result.data.sentenceTranslation || '')
|
||||
setGrammarCorrection(result.data.grammarCorrection || null)
|
||||
setFinalText(result.data.finalText || textInput)
|
||||
setSentenceAnalysis(result.data.WordAnalysis || {})
|
||||
setSentenceMeaning(result.data.SentenceMeaning?.Translation || '')
|
||||
setGrammarCorrection(result.data.GrammarCorrection || null)
|
||||
setFinalText(result.data.FinalAnalysisText || textInput)
|
||||
setShowAnalysisView(true)
|
||||
setUsageCount(prev => prev + 1)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -104,10 +104,26 @@ export function ClickableTextV2({
|
|||
}
|
||||
}
|
||||
|
||||
// 輔助函數:兼容大小寫屬性名稱
|
||||
// 輔助函數:兼容大小寫屬性名稱和處理AI資料格式
|
||||
const getWordProperty = (wordData: any, propName: string) => {
|
||||
const lowerProp = propName.toLowerCase()
|
||||
const upperProp = propName.charAt(0).toUpperCase() + propName.slice(1)
|
||||
|
||||
// 特殊處理同義詞 - 如果AI沒有提供,返回空數組
|
||||
if (propName === 'synonyms') {
|
||||
return wordData?.[lowerProp] || wordData?.[upperProp] || []
|
||||
}
|
||||
|
||||
// 特殊處理例句 - 如果AI沒有提供,生成預設例句
|
||||
if (propName === 'example') {
|
||||
return wordData?.[lowerProp] || wordData?.[upperProp] || `This is an example sentence using ${wordData?.word || 'the word'}.`
|
||||
}
|
||||
|
||||
// 特殊處理例句翻譯
|
||||
if (propName === 'exampleTranslation') {
|
||||
return wordData?.[lowerProp] || wordData?.[upperProp] || `這是使用 ${wordData?.word || '該詞'} 的例句翻譯。`
|
||||
}
|
||||
|
||||
return wordData?.[lowerProp] || wordData?.[upperProp]
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue