# 智能填空題系統設計規格書

## 概述

將填空題的挖空邏輯從前端移至後端，建立智能的例句處理系統，支援詞彙變形識別和AI輔助挖空。

## 問題分析

### 當前問題
- 前端使用簡單正則 `\b${word}\b` 進行挖空
- 無法處理詞彙變形：`eat` vs `ate`、`go` vs `went`
- 挖空失敗時無替代方案，導致題目無法正常顯示

### 影響範圍
- 動詞變形：eat/ate、go/went、run/ran
- 名詞複數：cat/cats、child/children
- 形容詞比較級：good/better、bad/worse
- 過去分詞：break/broken、speak/spoken

## 系統架構設計

### 資料庫結構調整

#### Flashcard 實體新增欄位
```csharp
[MaxLength(1000)]
public string? FilledQuestionText { get; set; }  // 挖空後的題目文字
```

#### 範例資料
```json
{
  "word": "ate",
  "example": "She ate an apple yesterday.",
  "filledQuestionText": "She ____ an apple yesterday."
}
```

### 後端服務架構

#### 1. BlankGenerationService 服務
```csharp
public interface IBlankGenerationService
{
    Task<string?> GenerateBlankQuestionAsync(string word, string example);
    string? TryProgrammaticBlank(string word, string example);
    Task<string?> GenerateAIBlankAsync(string word, string example);
}
```

#### 2. 智能挖空處理流程

##### Step 1: 程式碼挖空 (快速處理)
```csharp
// 1. 完全匹配
var regex1 = new Regex($@"\b{Regex.Escape(word)}\b", RegexOptions.IgnoreCase);

// 2. 常見變形規則
var variations = GetCommonVariations(word);
foreach(var variation in variations)
{
    var regex2 = new Regex($@"\b{Regex.Escape(variation)}\b", RegexOptions.IgnoreCase);
    // 嘗試替換
}
```

##### Step 2: AI 輔助挖空 (處理複雜變形)
```csharp
var prompt = $@"
請將以下例句中與詞彙「{word}」相關的詞挖空，用____替代：

詞彙: {word}
例句: {example}

規則:
1. 只挖空與目標詞彙相關的詞(包含變形、時態、複數等)
2. 用____替代被挖空的詞
3. 保持句子其他部分不變
4. 直接返回挖空後的句子，不要額外說明

挖空後的句子:";

await _geminiService.GenerateTextAsync(prompt);
```

#### 3. API 端點調整

##### GET /api/flashcards/due 強化邏輯
```csharp
foreach(var flashcard in dueCards)
{
    if(string.IsNullOrEmpty(flashcard.FilledQuestionText))
    {
        var blankQuestion = await _blankGenerationService.GenerateBlankQuestionAsync(
            flashcard.Word, flashcard.Example);

        if(!string.IsNullOrEmpty(blankQuestion))
        {
            flashcard.FilledQuestionText = blankQuestion;
            // 更新資料庫
        }
    }
}
```

##### 新增重新生成端點
```csharp
[HttpPost("{id}/regenerate-blank")]
public async Task<ActionResult> RegenerateBlankQuestion(Guid id)
```

### 前端架構簡化

#### SentenceFillTest 組件調整
```typescript
// 移除複雜的 renderSentenceWithInput() 邏輯
// 改為簡單的模板渲染

interface SentenceFillTestProps {
  word: string;
  definition: string;
  example: string;           // 原始例句
  filledQuestionText: string; // 挖空後的題目
  // ... 其他屬性
}

// 簡化的渲染邏輯
const renderFilledSentence = () => {
  return filledQuestionText.replace('____',
    `<input value="${fillAnswer}" ... />`
  );
}
```

## 實施計劃

### Phase 1: 資料庫結構
1. 創建 Migration 添加 `FilledQuestionText` 欄位
2. 更新 Flashcard 實體模型

### Phase 2: 後端服務開發
1. 實作 `BlankGenerationService`
2. 建立常見詞彙變形對應表
3. 整合 AI 挖空功能
4. 修改 FlashcardsController

### Phase 3: 前端優化
1. 簡化 SentenceFillTest 組件
2. 更新 Props 介面
3. 測試新的渲染邏輯

### Phase 4: 測試與優化
1. 測試各種詞彙變形情況
2. 驗證 AI 挖空品質
3. 效能優化和錯誤處理

## 預期效果

### 功能提升
- ✅ 支援所有詞彙變形挖空
- ✅ AI 輔助處理複雜情況
- ✅ 一次生成，多次使用
- ✅ 統一的挖空品質

### 技術優勢
- 🚀 前端邏輯簡化
- 🎯 後端統一處理
- 💾 結果快取提升效能
- 🤖 AI 確保準確性

### 維護性
- 📦 挖空邏輯集中管理
- 🔧 易於調整和優化
- 📊 可監控挖空成功率
- 🐛 錯誤處理更完善

## 風險評估

### 技術風險
- AI 調用可能失敗 → 提供降級策略
- 資料庫遷移 → 確保現有資料相容
- 效能影響 → 批次處理優化

### 緩解措施
- 多層回退機制 (程式碼 → AI → 手動)
- 非同步處理避免阻塞
- 詳細日誌記錄便於除錯