# 例句圖生成前後端完整整合計劃

## 📋 **項目概覽**

**目標**: 將已實現的例句圖生成後端 API 完整整合到前端詞卡管理介面
**預估時間**: 6-9 小時
**複雜度**: 中等 (需要前後端協調)

---

## 🎯 **當前狀況評估**

### ✅ **已完成功能**
- **後端 API**: 完整的兩階段圖片生成系統 (Gemini + Replicate)
- **圖片壓縮**: 自動壓縮 1024x1024 → 512x512
- **資料庫設計**: 完整的圖片關聯表格和追蹤系統
- **API 測試**: 至少 1 次成功生成驗證
- **Git 安全**: wwwroot 已被忽略，API Keys 安全存儲

### ❌ **缺失功能**
- **後端資料整合**: FlashcardsController 未返回圖片資訊
- **前端 API 整合**: 所有圖片生成功能都未實現
- **前端狀態管理**: 沒有生成進度追蹤
- **用戶體驗**: 仍使用硬編碼圖片映射

---

## 🚀 **Phase 1: 後端資料整合 (1-2 小時)**

### 🎯 **目標**: 讓 flashcards API 返回圖片資訊

#### **1.1 修改 FlashcardsController (30分鐘)**
```csharp
// 當前查詢
var flashcards = await _context.Flashcards
    .Where(f => f.UserId == userId)
    .ToListAsync();

// 改為包含圖片關聯
var flashcards = await _context.Flashcards
    .Include(f => f.FlashcardExampleImages)
        .ThenInclude(fei => fei.ExampleImage)
    .Where(f => f.UserId == userId)
    .ToListAsync();
```

#### **1.2 擴展 FlashcardDto (30分鐘)**
```csharp
public class FlashcardDto
{
    // 現有欄位...

    // 新增圖片相關欄位
    public List<ExampleImageDto> ExampleImages { get; set; } = new();
    public bool HasExampleImage => ExampleImages.Any();
    public string? PrimaryImageUrl => ExampleImages.FirstOrDefault(img => img.IsPrimary)?.ImageUrl;
}

public class ExampleImageDto
{
    public string Id { get; set; }
    public string ImageUrl { get; set; }
    public bool IsPrimary { get; set; }
    public decimal? QualityScore { get; set; }
}
```

#### **1.3 添加圖片 URL 生成邏輯 (30分鐘)**
```csharp
private async Task<List<ExampleImageDto>> MapExampleImages(List<FlashcardExampleImage> flashcardImages)
{
    var result = new List<ExampleImageDto>();

    foreach (var item in flashcardImages)
    {
        var imageUrl = await _imageStorageService.GetImageUrlAsync(item.ExampleImage.RelativePath);

        result.Add(new ExampleImageDto
        {
            Id = item.ExampleImage.Id.ToString(),
            ImageUrl = imageUrl,
            IsPrimary = item.IsPrimary,
            QualityScore = item.ExampleImage.QualityScore
        });
    }

    return result;
}
```

#### **1.4 測試後端更新 (30分鐘)**
- 驗證 API 回應包含圖片資訊
- 確認圖片 URL 正確生成
- 測試有圖片和無圖片的詞卡

---

## 🎨 **Phase 2: 前端 API 服務整合 (2-3 小時)**

### 🎯 **目標**: 創建完整的前端圖片生成服務

#### **2.1 創建圖片生成 API 服務 (1小時)**
**檔案**: `/frontend/lib/services/imageGeneration.ts`
```typescript
export interface ImageGenerationRequest {
  style: 'cartoon' | 'realistic' | 'minimal';
  priority: 'normal' | 'high' | 'low';
  replicateModel: string;
  options: {
    useGeminiCache: boolean;
    useImageCache: boolean;
    maxRetries: number;
    learnerLevel: string;
    scenario: string;
  };
}

export interface GenerationStatus {
  requestId: string;
  overallStatus: string;
  stages: {
    gemini: StageStatus;
    replicate: StageStatus;
  };
  result?: {
    imageUrl: string;
    imageId: string;
  };
}

export class ImageGenerationService {
  async generateImage(flashcardId: string, request: ImageGenerationRequest): Promise<{requestId: string}> {
    // 調用 POST /api/imagegeneration/flashcards/{flashcardId}/generate
  }

  async getGenerationStatus(requestId: string): Promise<GenerationStatus> {
    // 調用 GET /api/imagegeneration/requests/{requestId}/status
  }

  async pollUntilComplete(requestId: string, onProgress?: (status: GenerationStatus) => void): Promise<GenerationStatus> {
    // 輪詢直到完成
  }
}
```

#### **2.2 創建 React Hook (1小時)**
**檔案**: `/frontend/hooks/useImageGeneration.ts`
```typescript
export const useImageGeneration = () => {
  const [generationStates, setGenerationStates] = useState<Record<string, GenerationState>>({});

  const generateImage = async (flashcardId: string) => {
    // 啟動生成流程
    // 更新狀態為 generating
    // 開始輪詢進度
  };

  const getGenerationState = (flashcardId: string) => {
    return generationStates[flashcardId] || { status: 'idle' };
  };

  return { generateImage, getGenerationState };
};
```

#### **2.3 更新 flashcards 服務 (30分鐘)**
**檔案**: `/frontend/lib/services/flashcards.ts`
```typescript
export interface Flashcard {
  // 現有欄位...

  // 新增圖片欄位
  exampleImages: ExampleImage[];
  hasExampleImage: boolean;
  primaryImageUrl?: string;
}

export interface ExampleImage {
  id: string;
  imageUrl: string;
  isPrimary: boolean;
  qualityScore?: number;
}
```

---

## 🎮 **Phase 3: 前端 UI 整合 (2-3 小時)**

### 🎯 **目標**: 完整的用戶介面功能

#### **3.1 修改圖片顯示邏輯 (1小時)**
**檔案**: `/frontend/app/flashcards/page.tsx`

```typescript
// 移除硬編碼映射
const getExampleImage = (card: Flashcard): string | null => {
  return card.primaryImageUrl || null;
};

const hasExampleImage = (card: Flashcard): boolean => {
  return card.hasExampleImage;
};
```

#### **3.2 實現圖片生成功能 (1小時)**
```typescript
const { generateImage, getGenerationState } = useImageGeneration();

const handleGenerateExampleImage = async (card: Flashcard) => {
  try {
    setGeneratingCards(prev => new Set([...prev, card.id]));

    await generateImage(card.id);

    // 生成完成後刷新詞卡列表
    await searchActions.refresh();

    toast.success(`「${card.word}」的例句圖片生成完成！`);
  } catch (error) {
    toast.error(`圖片生成失敗: ${error.message}`);
  } finally {
    setGeneratingCards(prev => {
      const newSet = new Set(prev);
      newSet.delete(card.id);
      return newSet;
    });
  }
};
```

#### **3.3 添加生成進度 UI (30分鐘)**
```typescript
const GenerationProgress = ({ flashcardId }: { flashcardId: string }) => {
  const generationState = getGenerationState(flashcardId);

  if (generationState.status === 'generating') {
    return (
      <div className="flex items-center gap-2 text-blue-600">
        <Spinner className="w-4 h-4" />
        <span className="text-xs">
          {generationState.currentStage === 'description_generation' ? '生成描述中...' : '生成圖片中...'}
        </span>
      </div>
    );
  }

  return null;
};
```

#### **3.4 錯誤處理和重試 (30分鐘)**
```typescript
const RetryButton = ({ flashcardId, onRetry }: RetryButtonProps) => {
  return (
    <button
      onClick={() => onRetry(flashcardId)}
      className="text-xs text-red-600 hover:text-red-800"
    >
      重試生成
    </button>
  );
};
```

---

## 🧪 **Phase 4: 測試與部署 (1 小時)**

### **4.1 功能測試 (30分鐘)**
- 完整的圖片生成流程測試
- 多詞卡並發生成測試
- 錯誤情境測試 (網路中斷、API 失敗等)

### **4.2 用戶體驗優化 (20分鐘)**
- 載入動畫調整
- 成功/失敗訊息優化
- 響應式顯示調整

### **4.3 文檔更新 (10分鐘)**
- 更新使用說明
- 記錄整合完成狀態

---

## 📊 **成功指標**

### **功能指標**
- ✅ 點擊"新增例句圖"按鈕能啟動實際生成
- ✅ 能看到即時的生成進度 (描述生成 → 圖片生成)
- ✅ 生成完成後圖片立即顯示在詞卡中
- ✅ 錯誤處理優雅，用戶體驗流暢

### **技術指標**
- ✅ 前端完全不依賴硬編碼圖片映射
- ✅ 所有圖片資訊從後端 API 動態載入
- ✅ 支援多張圖片的詞卡
- ✅ 完整的狀態管理和錯誤處理

### **用戶體驗指標**
- ✅ 生成進度清楚可見 (預計 2-3 分鐘)
- ✅ 可以並發生成多個詞卡的圖片
- ✅ 響應式設計在各裝置正常顯示

---

## 🎛️ **實施建議**

### **建議順序**
1. **先完成後端整合** - 確保資料正確返回
2. **再進行前端整合** - 逐步替換硬編碼邏輯
3. **最後優化體驗** - 完善 UI 和錯誤處理

### **風險控制**
- **漸進式替換**: 保留硬編碼映射作為 fallback
- **功能開關**: 可以暫時關閉圖片生成功能
- **測試優先**: 每個階段都要充分測試

---

**文檔版本**: v1.0
**建立日期**: 2025-09-24
**預估完成**: 2025-09-25
**負責團隊**: 全端開發團隊