dramaling-vocab-learning/EXAMPLE_IMAGE_FRONTEND_BACK...

8.7 KiB
Raw Blame History

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

📋 項目概覽

目標: 將已實現的例句圖生成後端 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分鐘)

// 當前查詢
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分鐘)

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分鐘)

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

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

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

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

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

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

3.2 實現圖片生成功能 (1小時)

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分鐘)

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分鐘)

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 負責團隊: 全端開發團隊