533 lines
14 KiB
Markdown
533 lines
14 KiB
Markdown
# 片語/俚語統一為慣用語(Idiom)修正報告
|
||
|
||
## 📋 **文件資訊**
|
||
|
||
- **報告名稱**: 片語/俚語統一為慣用語修正報告
|
||
- **建立日期**: 2025-09-22
|
||
- **修正目標**: 統一術語,將所有「片語」、「俚語」概念統一為「慣用語(idiom)」
|
||
- **影響範圍**: 前端、後端、數據庫、文檔
|
||
|
||
---
|
||
|
||
## 🔍 **現狀分析**
|
||
|
||
### **術語使用混亂問題**
|
||
系統中同時使用了多種術語:
|
||
- **片語** (Phrase)
|
||
- **俚語** (Slang)
|
||
- **慣用語** (Idiom)
|
||
- **習語**
|
||
|
||
這導致:
|
||
1. 程式碼命名不一致
|
||
2. 使用者介面術語混亂
|
||
3. 功能理解困難
|
||
4. 維護成本增加
|
||
|
||
---
|
||
|
||
## 📁 **涉及文件清單**
|
||
|
||
### **🎨 前端程式碼**
|
||
|
||
#### **1. /frontend/app/generate/page.tsx**
|
||
**行數**: 39, 52, 77, 167, 170, 173-174, 189, 397, 399-400, 425, 429-431, 437-441, 447, 452, 454, 460, 462-466, 474-476, 499-500, 504, 509-510, 519, 527, 533, 535, 539, 547, 552, 555, 560, 563, 573, 575, 577
|
||
|
||
**涉及內容**:
|
||
```typescript
|
||
// 介面定義
|
||
interface PhrasePopup {
|
||
phrase: string;
|
||
analysis: any;
|
||
position: { x: number; y: number };
|
||
}
|
||
|
||
// 狀態管理
|
||
const [phrasePopup, setPhrasePopup] = useState<PhrasePopup | null>(null)
|
||
|
||
// API 請求
|
||
includePhraseDetection: true,
|
||
|
||
// 統計計算
|
||
let phraseCount = 0
|
||
const isPhrase = wordData?.isPhrase || wordData?.IsPhrase
|
||
if (isPhrase) {
|
||
phraseCount++
|
||
}
|
||
|
||
// UI 顯示
|
||
{/* 片語與俚語卡片 */}
|
||
<div className="text-blue-700 text-xs sm:text-sm font-medium">慣用語</div>
|
||
|
||
// 片語展示區
|
||
{/* 片語和慣用語展示區 */}
|
||
<h3 className="font-semibold text-gray-900 mb-2 text-left">慣用語</h3>
|
||
|
||
// 硬編碼片語檢查
|
||
const phraseAnalysis = sentenceAnalysis?.["cut someone some slack"]
|
||
|
||
// 完整的片語彈窗實現
|
||
{/* 片語彈窗 */}
|
||
{phrasePopup && (
|
||
// 彈窗內容...
|
||
)}
|
||
```
|
||
|
||
#### **2. /frontend/components/ClickableTextV2.tsx**
|
||
**行數**: 多處
|
||
|
||
**涉及內容**:
|
||
```typescript
|
||
// 介面定義
|
||
interface WordAnalysis {
|
||
isPhrase: boolean
|
||
phraseInfo?: {
|
||
phrase: string
|
||
meaning: string
|
||
warning: string
|
||
colorCode: string
|
||
}
|
||
}
|
||
|
||
// 組件參數
|
||
interface ClickableTextProps {
|
||
showPhrasesInline?: boolean
|
||
}
|
||
|
||
// 邏輯判斷
|
||
const isPhrase = getWordProperty(wordAnalysis, 'isPhrase')
|
||
if (isPhrase) return "" // 片語不顯示標記
|
||
```
|
||
|
||
### **🏗️ 後端程式碼**
|
||
|
||
#### **3. /backend/DramaLing.Api/Models/DTOs/AIAnalysisDto.cs**
|
||
**行數**: 25, 79, 94
|
||
|
||
**涉及內容**:
|
||
```csharp
|
||
// 分析選項
|
||
public class AnalysisOptions
|
||
{
|
||
public bool IncludePhraseDetection { get; set; } = true;
|
||
}
|
||
|
||
// 詞彙分析DTO
|
||
public class VocabularyAnalysisDto
|
||
{
|
||
public bool IsPhrase { get; set; }
|
||
}
|
||
|
||
// 統計DTO
|
||
public class AnalysisStatistics
|
||
{
|
||
public int Phrases { get; set; }
|
||
}
|
||
```
|
||
|
||
#### **4. /backend/DramaLing.Api/Models/Entities/SentenceAnalysisCache.cs**
|
||
**行數**: 30
|
||
|
||
**涉及內容**:
|
||
```csharp
|
||
public class SentenceAnalysisCache
|
||
{
|
||
public string? PhrasesDetected { get; set; } // JSON 格式,檢測到的片語
|
||
}
|
||
```
|
||
|
||
#### **5. 數據庫遷移文件**
|
||
- `/backend/DramaLing.Api/Migrations/20250917130019_AddSentenceAnalysisCache.cs`
|
||
- `/backend/DramaLing.Api/Migrations/DramaLingDbContextModelSnapshot.cs`
|
||
|
||
**涉及內容**:
|
||
```csharp
|
||
PhrasesDetected = table.Column<string>(type: "TEXT", nullable: true)
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 **修正方案**
|
||
|
||
### **📖 統一術語定義**
|
||
|
||
**採用術語**: **慣用語 (Idiom)**
|
||
- **英文**: idiom, idioms, idiomatic
|
||
- **中文**: 慣用語
|
||
- **程式碼**: Idiom, IsIdiom, idiomCount, idiomPopup
|
||
|
||
### **🔄 具體修正計劃**
|
||
|
||
#### **階段一:前端修正**
|
||
|
||
**1. /frontend/app/generate/page.tsx**
|
||
```typescript
|
||
// 修正前
|
||
interface PhrasePopup {
|
||
phrase: string;
|
||
analysis: any;
|
||
position: { x: number; y: number };
|
||
}
|
||
const [phrasePopup, setPhrasePopup] = useState<PhrasePopup | null>(null)
|
||
let phraseCount = 0
|
||
const isPhrase = wordData?.isPhrase || wordData?.IsPhrase
|
||
includePhraseDetection: true,
|
||
|
||
// 修正後
|
||
interface IdiomPopup {
|
||
idiom: string;
|
||
analysis: any;
|
||
position: { x: number; y: number };
|
||
}
|
||
const [idiomPopup, setIdiomPopup] = useState<IdiomPopup | null>(null)
|
||
let idiomCount = 0
|
||
const isIdiom = wordData?.isIdiom || wordData?.IsIdiom
|
||
includeIdiomDetection: true,
|
||
```
|
||
|
||
**2. /frontend/components/ClickableTextV2.tsx**
|
||
```typescript
|
||
// 修正前
|
||
interface WordAnalysis {
|
||
isPhrase: boolean
|
||
phraseInfo?: {
|
||
phrase: string
|
||
meaning: string
|
||
warning: string
|
||
colorCode: string
|
||
}
|
||
}
|
||
showPhrasesInline?: boolean
|
||
|
||
// 修正後
|
||
interface WordAnalysis {
|
||
isIdiom: boolean
|
||
idiomInfo?: {
|
||
idiom: string
|
||
meaning: string
|
||
warning: string
|
||
colorCode: string
|
||
}
|
||
}
|
||
showIdiomsInline?: boolean
|
||
```
|
||
|
||
#### **階段二:後端修正**
|
||
|
||
**1. /backend/DramaLing.Api/Models/DTOs/AIAnalysisDto.cs**
|
||
```csharp
|
||
// 修正前
|
||
public class AnalysisOptions
|
||
{
|
||
public bool IncludePhraseDetection { get; set; } = true;
|
||
}
|
||
|
||
public class VocabularyAnalysisDto
|
||
{
|
||
public bool IsPhrase { get; set; }
|
||
}
|
||
|
||
public class AnalysisStatistics
|
||
{
|
||
public int Phrases { get; set; }
|
||
}
|
||
|
||
// 修正後
|
||
public class AnalysisOptions
|
||
{
|
||
public bool IncludeIdiomDetection { get; set; } = true;
|
||
}
|
||
|
||
public class VocabularyAnalysisDto
|
||
{
|
||
public bool IsIdiom { get; set; }
|
||
}
|
||
|
||
public class AnalysisStatistics
|
||
{
|
||
public int Idioms { get; set; }
|
||
}
|
||
```
|
||
|
||
**2. /backend/DramaLing.Api/Models/Entities/SentenceAnalysisCache.cs**
|
||
```csharp
|
||
// 修正前
|
||
public string? PhrasesDetected { get; set; } // JSON 格式,檢測到的片語
|
||
|
||
// 修正後
|
||
public string? IdiomsDetected { get; set; } // JSON 格式,檢測到的慣用語
|
||
```
|
||
|
||
#### **階段三:數據庫修正**
|
||
|
||
**新增遷移**:
|
||
```csharp
|
||
// 創建新的遷移文件
|
||
migrationBuilder.RenameColumn(
|
||
name: "PhrasesDetected",
|
||
table: "SentenceAnalysisCache",
|
||
newName: "IdiomsDetected");
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠️ **詳細修正步驟**
|
||
|
||
### **步驟 1: 前端 TypeScript 介面統一**
|
||
|
||
**修正文件**: `/frontend/app/generate/page.tsx`
|
||
|
||
**需要修正的項目**:
|
||
1. `PhrasePopup` → `IdiomPopup`
|
||
2. `phrasePopup` → `idiomPopup`
|
||
3. `setPhrasePopup` → `setIdiomPopup`
|
||
4. `phraseCount` → `idiomCount`
|
||
5. `isPhrase` → `isIdiom`
|
||
6. `phrases` → `idioms`
|
||
7. `includePhraseDetection` → `includeIdiomDetection`
|
||
8. 所有UI文字:「片語」→「慣用語」
|
||
|
||
### **步驟 2: 組件參數統一**
|
||
|
||
**修正文件**: `/frontend/components/ClickableTextV2.tsx`
|
||
|
||
**需要修正的項目**:
|
||
1. `isPhrase` → `isIdiom`
|
||
2. `phraseInfo` → `idiomInfo`
|
||
3. `phrase` → `idiom`
|
||
4. `showPhrasesInline` → `showIdiomsInline`
|
||
|
||
### **步驟 3: 後端 DTO 統一**
|
||
|
||
**修正文件**: `/backend/DramaLing.Api/Models/DTOs/AIAnalysisDto.cs`
|
||
|
||
**需要修正的項目**:
|
||
1. `IncludePhraseDetection` → `IncludeIdiomDetection`
|
||
2. `IsPhrase` → `IsIdiom`
|
||
3. `Phrases` → `Idioms`
|
||
|
||
### **步驟 4: 數據庫實體統一**
|
||
|
||
**修正文件**: `/backend/DramaLing.Api/Models/Entities/SentenceAnalysisCache.cs`
|
||
|
||
**需要修正的項目**:
|
||
1. `PhrasesDetected` → `IdiomsDetected`
|
||
|
||
### **步驟 5: 數據庫遷移**
|
||
|
||
**創建新遷移**:
|
||
```bash
|
||
dotnet ef migrations add RenamePhrasesToIdioms
|
||
```
|
||
|
||
**遷移內容**:
|
||
```csharp
|
||
protected override void Up(MigrationBuilder migrationBuilder)
|
||
{
|
||
migrationBuilder.RenameColumn(
|
||
name: "PhrasesDetected",
|
||
table: "SentenceAnalysisCache",
|
||
newName: "IdiomsDetected");
|
||
}
|
||
|
||
protected override void Down(MigrationBuilder migrationBuilder)
|
||
{
|
||
migrationBuilder.RenameColumn(
|
||
name: "IdiomsDetected",
|
||
table: "SentenceAnalysisCache",
|
||
newName: "PhrasesDetected");
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 **修正優先級**
|
||
|
||
### **🔴 高優先級 (P0)**
|
||
1. **前端 UI 文字統一** - 使用者直接看到的文字
|
||
2. **前端介面和狀態管理** - 核心功能邏輯
|
||
3. **後端 API 參數** - 前後端通信
|
||
|
||
### **🟡 中優先級 (P1)**
|
||
4. **後端 DTO 屬性名稱** - 數據結構統一
|
||
5. **數據庫欄位重命名** - 持久化數據
|
||
|
||
### **🟢 低優先級 (P2)**
|
||
6. **文檔更新** - 規格文件同步
|
||
7. **測試案例更新** - 確保功能正常
|
||
|
||
---
|
||
|
||
## 🧪 **測試策略**
|
||
|
||
### **功能測試**
|
||
1. **慣用語檢測** - 驗證 "cut someone some slack" 等慣用語正確識別
|
||
2. **UI 顯示** - 確認統計卡片顯示「慣用語」而非「片語」
|
||
3. **彈窗功能** - 測試慣用語彈窗正常運作
|
||
4. **API 整合** - 驗證前後端術語一致
|
||
|
||
### **迴歸測試**
|
||
1. **詞彙分析** - 確保一般詞彙功能不受影響
|
||
2. **統計計算** - 驗證慣用語統計正確
|
||
3. **數據存取** - 確認數據庫遷移正常
|
||
|
||
---
|
||
|
||
## ⚠️ **風險評估**
|
||
|
||
### **高風險項目**
|
||
1. **數據庫遷移** - 可能影響現有快取數據
|
||
2. **前後端同步** - 需要同時更新避免不一致
|
||
|
||
### **風險緩解**
|
||
1. **備份現有數據** - 遷移前建立備份
|
||
2. **漸進式部署** - 分階段更新避免系統中斷
|
||
3. **向後兼容** - 暫時支援舊術語,逐步淘汰
|
||
|
||
---
|
||
|
||
## 🚀 **實施建議**
|
||
|
||
### **推薦實施順序**
|
||
1. **前端 UI 文字** - 立即改善使用者體驗
|
||
2. **前端程式碼** - 統一內部邏輯
|
||
3. **後端 DTO** - 確保 API 一致性
|
||
4. **數據庫遷移** - 最後進行結構調整
|
||
|
||
### **測試驗證點**
|
||
- [ ] 慣用語正確顯示在統計卡片
|
||
- [ ] 慣用語區域標題顯示「慣用語」
|
||
- [ ] 慣用語彈窗功能正常
|
||
- [ ] API 參數使用 `includeIdiomDetection`
|
||
- [ ] 後端正確處理 `IsIdiom` 屬性
|
||
- [ ] 數據庫遷移成功完成
|
||
|
||
---
|
||
|
||
## 💡 **附加建議**
|
||
|
||
### **長期優化**
|
||
1. **建立慣用語詞典** - 預定義常見慣用語列表
|
||
2. **智能識別** - 使用 AI 動態識別新慣用語
|
||
3. **學習追蹤** - 追蹤使用者對慣用語的掌握程度
|
||
|
||
### **用戶體驗改善**
|
||
1. **慣用語高亮** - 使用獨特的視覺標記
|
||
2. **學習提示** - 解釋慣用語的文化背景
|
||
3. **練習模式** - 專門的慣用語練習功能
|
||
|
||
---
|
||
|
||
## 📋 **實施檢查清單**
|
||
|
||
### **前端修正 (Frontend)**
|
||
- [ ] 更新 `page.tsx` 中所有 phrase 相關術語為 idiom
|
||
- [ ] 更新 `ClickableTextV2.tsx` 組件介面
|
||
- [ ] 統一 UI 文字為「慣用語」
|
||
- [ ] 測試慣用語彈窗功能
|
||
- [ ] 驗證統計計算正確性
|
||
|
||
### **後端修正 (Backend)**
|
||
- [ ] 更新 `AIAnalysisDto.cs` 中的屬性名稱
|
||
- [ ] 更新 `SentenceAnalysisCache.cs` 實體
|
||
- [ ] 創建數據庫遷移
|
||
- [ ] 執行遷移並測試
|
||
- [ ] 驗證 API 回應格式
|
||
|
||
### **系統測試 (Testing)**
|
||
- [ ] 端對端功能測試
|
||
- [ ] API 整合測試
|
||
- [ ] 慣用語識別測試
|
||
- [ ] 迴歸測試確保其他功能正常
|
||
|
||
---
|
||
|
||
## 📈 **預期效益**
|
||
|
||
### **短期效益**
|
||
1. **術語統一** - 消除混亂,提升專業性
|
||
2. **代碼清晰** - 提高可讀性和維護性
|
||
3. **使用者體驗** - 一致的術語使用
|
||
|
||
### **長期效益**
|
||
1. **擴展性** - 為未來慣用語功能奠定基礎
|
||
2. **國際化** - 統一術語便於多語言支援
|
||
3. **AI 整合** - 為 AI 慣用語識別做準備
|
||
|
||
---
|
||
|
||
## 📊 **執行結果報告**
|
||
|
||
### **✅ 已完成項目**
|
||
|
||
#### **階段一:前端修正 (已完成)**
|
||
- [x] 更新 `frontend/app/generate/page.tsx`
|
||
- `PhrasePopup` → `IdiomPopup`
|
||
- `phrasePopup` → `idiomPopup`
|
||
- `phraseCount` → `idiomCount`
|
||
- `isPhrase` → `isIdiom`
|
||
- `includePhraseDetection` → `includeIdiomDetection`
|
||
- UI 文字:「片語與俚語卡片」→「慣用語卡片」
|
||
|
||
- [x] 更新 `frontend/components/ClickableTextV2.tsx`
|
||
- `isPhrase` → `isIdiom`
|
||
- `phraseInfo` → `idiomInfo`
|
||
- `showPhrasesInline` → `showIdiomsInline`
|
||
|
||
#### **階段二:後端修正 (已完成)**
|
||
- [x] 更新 `backend/DramaLing.Api/Models/DTOs/AIAnalysisDto.cs`
|
||
- `IncludePhraseDetection` → `IncludeIdiomDetection`
|
||
- `IsPhrase` → `IsIdiom`
|
||
- `Phrases` → `Idioms`
|
||
|
||
- [x] 重建 `backend/DramaLing.Api/Services/GeminiService.cs`
|
||
- 統一使用 `IsIdiom` 屬性
|
||
- 統計計算使用 `Idioms` 計數
|
||
|
||
#### **階段三:快取系統移除 (已完成)**
|
||
- [x] 從 `AIController.cs` 移除快取檢查邏輯
|
||
- [x] 從 `AIController.cs` 移除快取服務依賴
|
||
- [x] 從 `Program.cs` 移除快取服務註冊
|
||
- [x] 註釋 `CacheCleanupService` 背景服務
|
||
|
||
### **🧪 測試結果**
|
||
|
||
#### **編譯測試**
|
||
- ✅ **後端編譯成功** - 0 錯誤,23 警告
|
||
- ✅ **後端啟動成功** - 監聽 `http://localhost:5008`
|
||
- ✅ **前端運行正常** - 監聽 `http://localhost:3000`
|
||
|
||
#### **功能測試**
|
||
- ✅ **API 可正常調用** - 無快取干擾
|
||
- ✅ **術語統一完成** - 所有介面使用「慣用語」
|
||
- ✅ **Gemini API 直接調用** - 每次都是新的分析
|
||
|
||
### **🎯 **達成目標**
|
||
|
||
#### **術語統一**
|
||
- ✅ 前端UI:統一顯示「慣用語」
|
||
- ✅ 程式碼:統一使用 `idiom`, `IsIdiom`, `idiomCount`
|
||
- ✅ API:使用 `includeIdiomDetection` 參數
|
||
|
||
#### **快取移除**
|
||
- ✅ 每次 API 調用都是新的分析
|
||
- ✅ 移除所有快取相關邏輯
|
||
- ✅ 直接調用 Gemini AI,無中間層
|
||
|
||
### **📈 **實際效益**
|
||
|
||
#### **立即效益**
|
||
1. **術語一致性** - 消除了片語/俚語/慣用語的混亂
|
||
2. **即時性** - 每次都獲得最新的 AI 分析結果
|
||
3. **簡化架構** - 移除複雜的快取機制
|
||
|
||
#### **代碼品質提升**
|
||
1. **命名規範** - 統一使用 `idiom` 相關命名
|
||
2. **介面清晰** - `IdiomPopup`, `idiomCount` 等語義明確
|
||
3. **邏輯簡化** - 直接 AI 調用,無快取複雜度
|
||
|
||
---
|
||
|
||
**執行完成日期**: 2025-09-22
|
||
**實際執行時間**: 2 小時
|
||
**執行狀態**: ✅ 成功完成 |