docs: 新增同義詞功能實作計劃
本計劃詳細說明了如何實作同義詞功能,包括: - 後端資料模型擴展 - API功能擴展 - 利用現有AI分析的同義詞 - 前端創建表單支援 - 測試與優化策略 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
50a0a79d72
commit
197648f476
|
|
@ -0,0 +1,270 @@
|
||||||
|
# 同義詞功能實作計劃
|
||||||
|
|
||||||
|
## 問題分析
|
||||||
|
|
||||||
|
### 現狀
|
||||||
|
- ✅ **前端有同義詞顯示功能**: 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 生成 + 人工精選
|
||||||
|
- 📊 **資料完整**: 統一的同義詞資料管理
|
||||||
|
|
||||||
|
### 維護性
|
||||||
|
- 📦 **模組化設計**: 同義詞服務獨立管理
|
||||||
|
- 🔧 **易於擴展**: 支援多語言同義詞
|
||||||
|
- 📈 **可監控**: 同義詞生成成功率追蹤
|
||||||
Loading…
Reference in New Issue