dramaling-vocab-learning/同義詞功能實作計劃.md

270 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 同義詞功能實作計劃
## 問題分析
### 現狀
-**前端有同義詞顯示功能**: FlipMemoryTest、詞卡詳情頁都有同義詞區塊
-**測試資料有同義詞**: example-data.json 包含同義詞資料
-**AI 已生成同義詞**: GeminiService 的 AnalyzeSentenceAsync 已包含同義詞提示詞和處理邏輯
-**後端實體缺少同義詞欄位**: Flashcard 模型沒有 Synonyms 屬性
-**同義詞未儲存**: AI 生成的同義詞沒有從分析結果提取並儲存到詞卡
-**API 不回傳同義詞**: GetFlashcards 不包含同義詞欄位
### 關鍵發現
**GeminiService.ConvertVocabularyAnalysis (第202行)**:
```csharp
Synonyms = aiWord.Synonyms ?? new List<string>(),
```
AI 分析已經包含同義詞,但這些資料沒有被儲存到 Flashcard 實體中
### 影響範圍
- AI 生成的同義詞被浪費,沒有儲存
- 詞卡詳情頁同義詞區塊永遠為空
- FlipMemoryTest 組件同義詞區塊不顯示
- 學習體驗不完整
---
## 實作計劃
### Phase 1: 後端資料模型擴展 (預計 0.5 天)
#### 1.1 更新 Flashcard 實體
**檔案**: `backend/DramaLing.Api/Models/Entities/Flashcard.cs`
```csharp
// 在 FilledQuestionText 欄位後添加
[MaxLength(1000)]
public string? Synonyms { get; set; } // JSON格式存儲同義詞陣列
```
#### 1.2 創建資料庫 Migration
```bash
dotnet ef migrations add AddSynonymsField
dotnet ef database update
```
#### 1.3 更新 DbContext 欄位映射
**檔案**: `backend/DramaLing.Api/Data/DramaLingDbContext.cs`
```csharp
private void ConfigureFlashcardEntity(ModelBuilder modelBuilder)
{
var flashcardEntity = modelBuilder.Entity<Flashcard>();
// ... 現有映射
flashcardEntity.Property(f => f.Synonyms).HasColumnName("synonyms");
}
```
### Phase 2: API 功能擴展 (預計 1 天)
#### 2.1 更新創建詞卡 DTO
**檔案**: `backend/DramaLing.Api/Models/DTOs/CreateFlashcardRequest.cs`
```csharp
public class CreateFlashcardRequest
{
// ... 現有屬性
public List<string>? Synonyms { get; set; }
}
```
#### 2.2 修改 FlashcardsController
**檔案**: `backend/DramaLing.Api/Controllers/FlashcardsController.cs`
##### CreateFlashcard 方法
```csharp
var flashcard = new Flashcard
{
// ... 現有欄位
Synonyms = request.Synonyms?.Any() == true
? JsonSerializer.Serialize(request.Synonyms)
: null,
};
```
##### GetFlashcards 方法 (查詢回應)
```csharp
flashcardDtos.Add(new
{
// ... 現有欄位
Synonyms = !string.IsNullOrEmpty(flashcard.Synonyms)
? JsonSerializer.Deserialize<List<string>>(flashcard.Synonyms) ?? new List<string>()
: new List<string>(),
});
```
#### 2.3 利用現有 AI 分析的同義詞
**關鍵發現**: GeminiService 的句子分析 **已經包含同義詞生成**
**現有邏輯** (GeminiService.cs 第70行):
```
"synonyms": ["synonym1", "synonym2"],
```
**現有處理** (第202行):
```csharp
Synonyms = aiWord.Synonyms ?? new List<string>(),
```
**問題**: 這些同義詞只存在於 AI 分析結果中,沒有儲存到 Flashcard 實體
**解決方案**: 修改詞卡創建流程,從 AI 分析結果提取同義詞並儲存
### Phase 3: 創建詞卡時自動生成同義詞 (預計 0.5 天)
#### 3.1 修改創建流程 - 從現有 AI 分析提取同義詞
**檔案**: `backend/DramaLing.Api/Controllers/FlashcardsController.cs`
**在 CreateFlashcard 方法中AI 分析後**:
```csharp
// 現有的 AI 分析邏輯
var analysisResult = await _analysisService.AnalyzeSentenceAsync(request.Example, options);
// 🆕 從 AI 分析結果提取目標詞彙的同義詞
var targetWordAnalysis = analysisResult.VocabularyAnalysis
.FirstOrDefault(kvp => kvp.Key.Equals(request.Word, StringComparison.OrdinalIgnoreCase));
List<string> synonyms = new();
if (targetWordAnalysis.Value != null && targetWordAnalysis.Value.Synonyms.Any())
{
synonyms = targetWordAnalysis.Value.Synonyms.Take(4).ToList();
_logger.LogInformation("Extracted {Count} synonyms for word: {Word}",
synonyms.Count, request.Word);
}
// 儲存同義詞到 Flashcard
flashcard.Synonyms = synonyms.Any()
? JsonSerializer.Serialize(synonyms)
: null;
```
#### 3.2 Alternative: 直接調用 AI 生成同義詞
**如果上述方法提取失敗,備用方案**:
```csharp
// 備用:直接為單詞生成同義詞
if (string.IsNullOrEmpty(flashcard.Synonyms))
{
var singleWordAnalysis = await _analysisService.AnalyzeSentenceAsync(
request.Word, new AnalysisOptions());
var wordSynonyms = singleWordAnalysis.VocabularyAnalysis
.FirstOrDefault().Value?.Synonyms ?? new List<string>();
flashcard.Synonyms = wordSynonyms.Any()
? JsonSerializer.Serialize(wordSynonyms)
: null;
}
```
### Phase 4: 前端創建表單支援 (預計 1 天)
#### 4.1 詞卡創建表單擴展
**檔案**: `frontend/app/generate/page.tsx` 或詞卡創建相關組件
```typescript
// 添加同義詞輸入區塊
const [synonyms, setSynonyms] = useState<string[]>([]);
// 同義詞管理功能
const addSynonym = (synonym: string) => {
if (synonym.trim() && !synonyms.includes(synonym.trim())) {
setSynonyms([...synonyms, synonym.trim()]);
}
};
const removeSynonym = (index: number) => {
setSynonyms(synonyms.filter((_, i) => i !== index));
};
```
#### 4.2 同義詞輸入 UI 組件
```tsx
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
同義詞 (可選)
</label>
{/* 已添加的同義詞 */}
<div className="flex flex-wrap gap-2 mb-2">
{synonyms.map((synonym, index) => (
<span key={index} className="bg-purple-100 text-purple-700 px-2 py-1 rounded-full text-sm">
{synonym}
<button onClick={() => removeSynonym(index)} className="ml-1 text-purple-500">×</button>
</span>
))}
</div>
{/* 添加新同義詞 */}
<input
type="text"
placeholder="輸入同義詞並按 Enter"
onKeyDown={(e) => {
if (e.key === 'Enter') {
addSynonym(e.currentTarget.value);
e.currentTarget.value = '';
}
}}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
/>
</div>
```
### Phase 5: 測試與優化 (預計 0.5 天)
#### 5.1 功能驗證
- [ ] 新創建的詞卡包含同義詞
- [ ] 詞卡詳情頁正確顯示同義詞
- [ ] FlipMemoryTest 組件顯示同義詞
- [ ] 同義詞 CRUD 功能正常
#### 5.2 資料遷移
- [ ] 為現有詞卡補充同義詞資料
- [ ] 批次生成常見詞彙的同義詞
- [ ] 驗證資料完整性
---
## 實施順序
### Week 1
- **Day 1**: Phase 1 (資料模型) + Phase 2 (API 功能)
- **Day 2**: Phase 3 (自動生成) + Phase 4 (前端表單)
### Week 2
- **Day 1**: Phase 5 (測試優化) + 資料遷移
- **Day 2**: 部署和監控
---
## 技術考量
### 資料存儲策略
- **JSON 格式**: 使用 JSON 字串存儲同義詞陣列
- **欄位長度**: MaxLength(1000) 支援多個同義詞
- **索引考量**: 暫不建立同義詞搜尋索引
### 效能優化
- **快取常見同義詞**: 避免重複 AI 調用
- **批次處理**: 新詞卡創建時批次生成同義詞
- **前端優化**: 使用 useMemo 處理同義詞資料
### 錯誤處理
- **AI 生成失敗**: 使用常見同義詞對應表降級
- **資料格式錯誤**: JSON 反序列化異常處理
- **前端容錯**: 空同義詞時隱藏區塊
---
## 預期效果
### 用戶體驗
-**完整的詞彙學習**: 同義詞豐富詞彙理解
-**自動化生成**: 無需手動輸入同義詞
-**彈性管理**: 支援手動編輯和添加
### 系統優勢
- 🚀 **學習深度**: 同義詞擴展詞彙掌握範圍
- 🤖 **智能輔助**: AI 生成 + 人工精選
- 📊 **資料完整**: 統一的同義詞資料管理
### 維護性
- 📦 **模組化設計**: 同義詞服務獨立管理
- 🔧 **易於擴展**: 支援多語言同義詞
- 📈 **可監控**: 同義詞生成成功率追蹤