# 例句圖生成功能產品需求規格書 (PRD) ## 1. 功能概述 ### 1.1 產品目標 為 DramaLing 詞彙學習平台開發智能例句圖生成功能,通過視覺化例句提升用戶學習效果和記憶保留率。 ### 1.2 核心價值主張 - **視覺記憶增強**:圖像結合文字,提高記憶效果 40-60% - **學習體驗優化**:直觀的視覺內容降低理解門檻 - **個性化學習**:根據用戶程度和偏好生成適配內容 - **成本效益平衡**:智能緩存和批量處理控制 AI 生成成本 ### 1.3 目標用戶 - **主要用戶**:英語學習者(A1-C2 所有等級) - **使用場景**:詞卡複習、新詞學習、例句理解 - **預期效果**:提升學習效率 30%,延長學習時間 25% ## 2. 系統架構設計 ### 2.1 雙環境架構策略 #### 2.1.1 開發環境 (Development) ``` 本地圖片儲存架構 ├── wwwroot/images/examples/ # 靜態圖片存放 ├── LocalImageStorageService # 本地檔案管理 ├── 快速測試與迭代 # 零雲端成本 └── 完整功能驗證 # 生產前測試 ``` #### 2.1.2 生產環境 (Production) ``` 雲端圖片儲存架構 ├── AWS S3 / Azure Blob # 雲端圖片儲存 ├── CDN 加速分發 # 全球訪問優化 ├── 自動備份與容災 # 數據安全保障 └── 彈性擴展與監控 # 效能管理 ``` ### 2.2 兩階段 AI 圖片生成架構 #### 2.2.1 第一階段:圖片描述生成 (Gemini AI) ``` 詞卡內容 → Gemini API → 優化的圖片描述 prompt ↓ ↓ ↓ 詞彙+例句 智能分析 詳細視覺描述 語境資訊 風格調整 生成參數優化 ``` - **Gemini 提示詞生成**:基於現有 GeminiAIProvider 服務 - **語境分析**:結合詞彙難度、學習者程度、例句內容 - **風格優化**:根據 CEFR 等級調整描述複雜度和視覺風格 - **成本效益**:重用現有 Gemini 整合,每次調用約 $0.001 #### 2.2.2 第二階段:圖片生成 (Replicate API) ``` 圖片描述 prompt → Replicate API → 高品質例句圖片 ↓ ↓ ↓ 優化提示詞 圖片生成模型 品質檢測 參數配置 (FLUX/SD XL) 內容審核 ``` - **Replicate 圖片生成**:使用 FLUX 或 Stable Diffusion XL 模型 - **多模型支援**:支援不同風格和品質需求 - **批量處理佇列**:非同步處理大量生成請求 - **品質檢測**:自動過濾不當或低品質內容 #### 2.2.3 圖片生成引擎整合 - **流程編排**:協調兩階段生成流程 - **錯誤處理**:單階段失敗時的重試和降級策略 - **狀態管理**:實時追蹤生成進度和狀態更新 - **成本優化**:智能調度和資源管理 #### 2.2.4 智能快取系統 - **雙階段快取**:Gemini 描述快取 + Replicate 圖片快取 - **語意快取**:類似例句共享相同圖片描述和最終圖片 - **多層快取策略**:記憶體 → 資料庫 → 檔案系統 - **快取失效機制**:基於使用頻率和時間的清理 - **預生成策略**:熱門詞彙預先生成描述和圖片 #### 2.2.5 儲存抽象層 ```csharp public interface IImageStorageService { Task SaveImageAsync(Stream imageStream, string fileName); Task GetImageUrlAsync(string imagePath); Task DeleteImageAsync(string imagePath); Task GetStorageInfoAsync(); } // 實現類別 - LocalImageStorageService // 開發環境 - CloudImageStorageService // 生產環境 - HybridImageStorageService // 混合策略 ``` ## 3. 資料庫設計 ### 3.1 核心數據表結構 #### 3.1.1 例句圖片表 (example_images) ```sql CREATE TABLE example_images ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), relative_path VARCHAR(500) NOT NULL, -- 圖片相對路徑 alt_text VARCHAR(200), -- 圖片描述文字 -- 兩階段生成相關欄位 gemini_prompt TEXT, -- Gemini 生成描述的原始提示詞 gemini_description TEXT, -- Gemini 生成的圖片描述 replicate_prompt TEXT, -- 最終傳給 Replicate 的優化提示詞 replicate_model VARCHAR(100), -- 使用的 Replicate 模型名稱 replicate_version VARCHAR(100), -- 模型版本號 -- 生成成本追蹤 gemini_cost DECIMAL(10,6), -- Gemini API 成本 replicate_cost DECIMAL(10,6), -- Replicate API 成本 total_generation_cost DECIMAL(10,6), -- 總生成成本 -- 原有欄位 file_size INTEGER, -- 檔案大小 (bytes) image_width INTEGER, -- 圖片寬度 image_height INTEGER, -- 圖片高度 content_hash VARCHAR(64) UNIQUE, -- 內容雜湊值 (防重複) quality_score DECIMAL(3,2), -- 品質評分 (0.00-1.00) moderation_status VARCHAR(20) DEFAULT 'pending', -- 審核狀態 moderation_notes TEXT, -- 審核備註 access_count INTEGER DEFAULT 0, -- 存取次數統計 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` #### 3.1.2 詞卡圖片關聯表 (flashcard_example_images) ```sql CREATE TABLE flashcard_example_images ( flashcard_id UUID REFERENCES flashcards(id) ON DELETE CASCADE, example_image_id UUID REFERENCES example_images(id) ON DELETE CASCADE, display_order INTEGER DEFAULT 1, -- 顯示順序 is_primary BOOLEAN DEFAULT false, -- 是否為主要圖片 context_relevance DECIMAL(3,2), -- 語境相關度評分 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (flashcard_id, example_image_id) ); ``` #### 3.1.3 圖片生成請求表 (image_generation_requests) ```sql CREATE TABLE image_generation_requests ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES user_profiles(id) ON DELETE CASCADE, flashcard_id UUID REFERENCES flashcards(id) ON DELETE CASCADE, -- 兩階段狀態追蹤 overall_status VARCHAR(20) DEFAULT 'pending', -- 總狀態: pending/description_generating/image_generating/completed/failed gemini_status VARCHAR(20) DEFAULT 'pending', -- Gemini 階段: pending/processing/completed/failed replicate_status VARCHAR(20) DEFAULT 'pending', -- Replicate 階段: pending/processing/completed/failed -- 請求內容 original_request TEXT NOT NULL, -- 原始請求內容 (詞卡資訊) gemini_prompt TEXT, -- 傳給 Gemini 的提示詞 generated_description TEXT, -- Gemini 生成的圖片描述 final_replicate_prompt TEXT, -- 最終傳給 Replicate 的提示詞 -- 結果和錯誤 generated_image_id UUID REFERENCES example_images(id), gemini_error_message TEXT, -- Gemini 階段錯誤訊息 replicate_error_message TEXT, -- Replicate 階段錯誤訊息 -- 效能追蹤 gemini_processing_time_ms INTEGER, -- Gemini 處理時間 replicate_processing_time_ms INTEGER, -- Replicate 處理時間 total_processing_time_ms INTEGER, -- 總處理時間 -- 成本追蹤 gemini_cost DECIMAL(10,6), -- Gemini API 成本 replicate_cost DECIMAL(10,6), -- Replicate API 成本 total_cost DECIMAL(10,6), -- 總成本 -- 時間戳記 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, gemini_started_at TIMESTAMP, gemini_completed_at TIMESTAMP, replicate_started_at TIMESTAMP, replicate_completed_at TIMESTAMP, completed_at TIMESTAMP ); ``` ### 3.2 索引優化策略 ```sql -- 查詢效能索引 CREATE INDEX idx_example_images_content_hash ON example_images(content_hash); CREATE INDEX idx_example_images_access_count ON example_images(access_count DESC); CREATE INDEX idx_flashcard_images_primary ON flashcard_example_images(flashcard_id, is_primary); CREATE INDEX idx_generation_requests_status ON image_generation_requests(generation_status, created_at); ``` ## 4. API 設計規範 ### 4.1 核心 API 端點 #### 4.1.1 生成例句圖片 (兩階段流程) ```http POST /api/flashcards/{flashcardId}/generate-example-image Authorization: Bearer {token} Content-Type: application/json Request Body: { "style": "cartoon|realistic|minimal", // 圖片風格偏好 "priority": "normal|high|low", // 生成優先級 "dimensions": { // 圖片尺寸要求 "width": 512, "height": 512 }, "generationOptions": { // 生成選項 "useGeminiCache": true, // 是否使用 Gemini 描述快取 "useImageCache": true, // 是否使用圖片快取 "maxRetries": 3 // 最大重試次數 }, "replicateModel": "flux-1-dev|stable-diffusion-xl", // Replicate 模型選擇 "additionalContext": { // 額外語境資訊 "learnerLevel": "B1", "scenario": "business|daily|academic", "visualPreferences": ["colorful", "simple", "realistic"] } } Response: { "success": true, "data": { "requestId": "uuid", "overallStatus": "pending", // pending/description_generating/image_generating/completed/failed "currentStage": "description_generation", // 當前執行階段 "estimatedTimeMinutes": { "gemini": 0.5, // Gemini 描述生成預估時間 "replicate": 2, // Replicate 圖片生成預估時間 "total": 2.5 }, "costEstimate": { "gemini": 0.001, // Gemini 成本預估 "replicate": 0.05, // Replicate 成本預估 "total": 0.051 }, "queuePosition": 3 // 佇列中的位置 } } ``` #### 4.1.2 獲取圖片生成狀態 (兩階段狀態追蹤) ```http GET /api/image-generation/requests/{requestId}/status Authorization: Bearer {token} Response (進行中): { "success": true, "data": { "requestId": "uuid", "overallStatus": "image_generating", "stages": { "gemini": { "status": "completed", "startedAt": "2025-09-24T10:28:00Z", "completedAt": "2025-09-24T10:28:15Z", "processingTimeMs": 15000, "cost": 0.0012, "generatedDescription": "A professional business meeting scene with diverse people sitting around a modern conference table. One person is gesturing while presenting an idea, with other colleagues listening attentively..." }, "replicate": { "status": "processing", "startedAt": "2025-09-24T10:28:20Z", "model": "flux-1-dev", "estimatedCompletionTime": "2025-09-24T10:30:30Z", "progress": "65%" } }, "totalProcessingTimeMs": 95000, "estimatedRemainingTimeMs": 45000 } } Response (完成): { "success": true, "data": { "requestId": "uuid", "overallStatus": "completed", "stages": { "gemini": { "status": "completed", "processingTimeMs": 15000, "cost": 0.0012, "generatedDescription": "A professional business meeting scene..." }, "replicate": { "status": "completed", "processingTimeMs": 125000, "cost": 0.048, "model": "flux-1-dev", "modelVersion": "dev-v1.2" } }, "result": { "imageUrl": "https://cdn.dramaling.com/images/examples/uuid.png", "imageId": "uuid", "qualityScore": 0.95, "dimensions": { "width": 512, "height": 512 }, "fileSize": 245760 }, "totalCost": 0.0492, "totalProcessingTimeMs": 140000, "completedAt": "2025-09-24T10:30:25Z" } } Response (失敗): { "success": true, "data": { "requestId": "uuid", "overallStatus": "failed", "failedStage": "replicate", "stages": { "gemini": { "status": "completed", "cost": 0.0012 }, "replicate": { "status": "failed", "error": "Content policy violation: Generated image contains inappropriate content", "retryCount": 3 } }, "totalCost": 0.0012, "canRetry": true, "suggestedAction": "modify_prompt" } } ``` #### 4.1.3 批量管理例句圖片 ```http GET /api/admin/example-images Authorization: Bearer {adminToken} Query Parameters: - status: pending|approved|rejected - provider: dalle3|midjourney - qualityScore: 0.8+ (minimum score) - dateFrom: 2025-09-01 - dateTo: 2025-09-30 - page: 1 - pageSize: 50 Response: { "success": true, "data": { "images": [...], "pagination": { "currentPage": 1, "totalPages": 10, "totalCount": 487 }, "statistics": { "pendingCount": 23, "approvedCount": 450, "rejectedCount": 14, "averageQualityScore": 0.89 } } } ``` ## 5. 用戶體驗設計 ### 5.1 互動流程設計 #### 5.1.1 主要使用流程 ``` 1. 用戶在詞卡頁面點擊「生成例句圖」 ↓ 2. 系統檢查現有圖片: - 有圖片 → 直接顯示 - 無圖片 → 進入生成流程 ↓ 3. 圖片生成流程: - 顯示生成中動畫 (預估 1-3 分鐘) - 提供取消選項 - 實時更新進度狀態 ↓ 4. 生成完成: - 自動刷新顯示新圖片 - 提供「重新生成」選項 - 收集用戶滿意度回饋 ``` #### 5.1.2 錯誤處理與回退機制 ``` 生成失敗處理: ├── 網路錯誤 → 自動重試 3 次 ├── AI 服務限制 → 提示稍後再試 ├── 內容不當 → 顯示預設圖片 └── 積分不足 → 引導購買或升級 ``` ### 5.2 視覺設計規範 #### 5.2.1 圖片容器設計 ```css .example-image-container { width: 100%; max-width: 400px; aspect-ratio: 4/3; border-radius: 12px; overflow: hidden; border: 2px solid var(--border-color); background: linear-gradient(135deg, #f5f5f5, #e8e8e8); } .loading-state { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; background: var(--loading-bg); } .generate-button { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; border-radius: 8px; padding: 12px 24px; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; } ``` #### 5.2.2 載入動畫設計 - **初始載入**:脈衝效果,顯示 "正在生成圖片..." - **處理中**:進度條,顯示預估剩餘時間 - **完成**:淡入效果,圖片平滑顯示 ## 6. 技術實現細節 ### 6.1 兩階段 AI 圖片生成整合 #### 6.1.1 第一階段:Gemini 圖片描述生成服務 ```csharp public class GeminiImageDescriptionService : IGeminiImageDescriptionService { private readonly GeminiAIProvider _geminiProvider; private readonly ILogger _logger; public async Task GenerateDescriptionAsync(Flashcard flashcard, GenerationOptions options) { var prompt = BuildGeminiPrompt(flashcard, options); try { var geminiResponse = await _geminiProvider.CallGeminiAPIAsync(prompt); var description = ExtractImageDescription(geminiResponse); return new ImageDescriptionResult { Success = true, Description = description, OptimizedPrompt = OptimizeForReplicate(description, options), Cost = CalculateGeminiCost(prompt), ProcessingTimeMs = stopwatch.ElapsedMilliseconds }; } catch (Exception ex) { _logger.LogError(ex, "Gemini description generation failed for flashcard {FlashcardId}", flashcard.Id); return new ImageDescriptionResult { Success = false, Error = ex.Message }; } } private string BuildGeminiPrompt(Flashcard flashcard, GenerationOptions options) { return $@"# 總覽 你是一位專業插畫設計師兼職英文老師,專門為英語學習教材製作插畫圖卡,用來幫助學生理解英文例句的意思。 # 詞卡資訊 - 詞彙:{flashcard.Word} - 中文翻譯:{flashcard.Translation} - 詞性:{flashcard.PartOfSpeech} - 例句:{flashcard.Example} - 難度等級:{flashcard.DifficultyLevel} # SOP 1. 根據上述英文例句,請撰寫一段圖像描述提示詞,用於提供圖片生成AI作為生成圖片的提示詞 2. 請將下方「風格指南」的所有要求加入提示詞中 3. 並於圖片提示詞最後加上:「Absolutely no visible text, characters, letters, numbers, symbols, handwriting, labels, or any form of writing anywhere in the image — including on signs, books, clothing, screens, or backgrounds.」 # 圖片提示詞規範 ## 情境清楚 1. 角色描述具體清楚 - 明確指出圖中有哪些人物,包含性別、年齡、外觀特徵或服裝 - 如有兩人以上,需說明他們彼此的關係或互動狀態(如:母女、朋友、陌生人等) 2. 動作明確具象 - 說明主角正在做的動作,須是能被具體畫出來的動作(如:喝咖啡、講電話、跑步) - 若動作帶有情緒(如:生氣地講電話、緊張地看著別人),請加入情緒描述以利傳達語意 - 人物比例正常、表情自然、生動但不誇張 3. 場景明確具體 - 指出事件發生的地點(如:公園、教室、咖啡廳、城市街道) - 可補充時間(如:早上、傍晚)與天氣(如:下雨、晴天),幫助構圖更清楚 4. 物品明確具體 - 若例句中包含物品(如:書、手機、餐點、雨傘等),必須清楚描述物品的種類、外觀特徵、位置與用途 - 避免模糊詞(如 ""some stuff""、""a thing""),應具體指出是什麼物品 - 若物品為主題核心,請描述其使用情境或與人物的互動方式 - 若出現多個物品,需明確指示其關係與空間位置 - 所有物品須為日常生活中常見物件,避免使用過於抽象或符號化的圖像 5. 語意需與原句一致 - 提示詞必須忠實呈現英文句子的核心意思 - 若英文句含有抽象概念或隱喻,請轉化為對應的具象場景 6. 避免過於抽象或象徵性符號 - 圖片必須用生活中常見的情境、物體或角色表現,避免使用抽象圖形來傳達語意 - 圖片中不要出現任何文字 ## 風格指南 - 風格類型:扁平插畫(Flat Illustration) - 線條特徵:無描邊線條(outline-less) - 色調:暖色調、柔和、低飽和 - 人物樣式:簡化卡通人物,表情自然,不誇張 - 背景構成:圖形簡化(如樹、草地),使用色塊區分層次 - 整體氛圍:溫馨、平靜、適合教育情境 - 技術風格:無紋理、無漸層、無光影寫實感 請根據以上規範,為這個英文例句生成圖片描述提示詞,並確保完全符合風格指南要求。"; } private string OptimizeForReplicate(string description, GenerationOptions options) { // Gemini 已經包含完整的風格指南,這裡只需要確保符合 Ideogram 模型要求 var optimizedPrompt = description; // 確保包含扁平插畫風格要求 if (!optimizedPrompt.Contains("flat illustration")) { optimizedPrompt += ". Style guide: flat illustration style, outline-less shapes, warm and soft color tones, low saturation, cartoon-style characters with natural expressions, simplified background with color blocks, cozy and educational atmosphere, no texture, no gradients, no photorealism, no fantasy elements."; } // 強制加入禁止文字的規則 if (!optimizedPrompt.Contains("Absolutely no visible text")) { optimizedPrompt += " Absolutely no visible text, characters, letters, numbers, symbols, handwriting, labels, or any form of writing anywhere in the image — including on signs, books, clothing, screens, or backgrounds."; } return optimizedPrompt; } } ``` #### 6.1.2 第二階段:Replicate 圖片生成服務 ```csharp public class ReplicateImageGenerationService : IReplicateImageGenerationService { private readonly HttpClient _httpClient; private readonly ReplicateOptions _options; private readonly ILogger _logger; public async Task GenerateImageAsync(string prompt, ReplicateModel model, GenerationOptions options) { var requestPayload = BuildReplicateRequest(prompt, model, options); try { // 啟動 Replicate 預測 var predictionResponse = await StartPredictionAsync(requestPayload); // 輪詢檢查生成狀態 var result = await WaitForCompletionAsync(predictionResponse.Id, options.TimeoutMinutes); return result; } catch (Exception ex) { _logger.LogError(ex, "Replicate image generation failed"); return new ImageGenerationResult { Success = false, Error = ex.Message }; } } private object BuildReplicateRequest(string prompt, ReplicateModel model, GenerationOptions options) { return model.Name switch { "ideogram-v2a-turbo" => new { version = "c169dbd9a03b7bd35c3b05aa91e83bc4ad23ee2a4b8f93f2b6cbdda4f466de4a", input = new { prompt = prompt, width = options.Width ?? 512, height = options.Height ?? 512, magic_prompt_option = "Auto", // Ideogram 特有參數 style_type = "General", // 適合教育用途的一般風格 aspect_ratio = "ASPECT_1_1", // 1:1 比例適合詞卡 model = "V_2_TURBO", // 使用 Turbo 版本 seed = options.Seed ?? Random.Shared.Next() } }, "flux-1-dev" => new { input = new { prompt = prompt, width = options.Width ?? 512, height = options.Height ?? 512, num_outputs = 1, guidance_scale = 3.5, num_inference_steps = 28, seed = options.Seed ?? Random.Shared.Next() } }, "stable-diffusion-xl" => new { input = new { prompt = prompt, width = options.Width ?? 512, height = options.Height ?? 512, num_outputs = 1, scheduler = "K_EULER_ANCESTRAL", num_inference_steps = 25, guidance_scale = 7.5, seed = options.Seed ?? Random.Shared.Next() } }, _ => throw new NotSupportedException($"Model {model.Name} not supported") }; } private async Task StartPredictionAsync(object requestPayload) { var json = JsonSerializer.Serialize(requestPayload); var content = new StringContent(json, Encoding.UTF8, "application/json"); // 使用 Ideogram V2 Turbo 的 API 端點 var response = await _httpClient.PostAsync( "https://api.replicate.com/v1/models/ideogram-ai/ideogram-v2a-turbo/predictions", content); response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize(responseJson); } private async Task WaitForCompletionAsync(string predictionId, int timeoutMinutes) { var timeout = TimeSpan.FromMinutes(timeoutMinutes); var pollInterval = TimeSpan.FromSeconds(2); var startTime = DateTime.UtcNow; while (DateTime.UtcNow - startTime < timeout) { var status = await GetPredictionStatusAsync(predictionId); switch (status.Status) { case "succeeded": return new ImageGenerationResult { Success = true, ImageUrl = status.Output?.FirstOrDefault()?.ToString(), ProcessingTimeMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds, Cost = CalculateReplicateCost(status.Metrics), ModelVersion = status.Version }; case "failed": return new ImageGenerationResult { Success = false, Error = status.Error?.ToString() ?? "Generation failed", ProcessingTimeMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds }; case "processing": await Task.Delay(pollInterval); break; } } return new ImageGenerationResult { Success = false, Error = "Generation timeout exceeded" }; } } ``` #### 6.1.3 兩階段流程編排服務 ```csharp public class ImageGenerationOrchestrator : IImageGenerationOrchestrator { private readonly IGeminiImageDescriptionService _geminiService; private readonly IReplicateImageGenerationService _replicateService; private readonly IImageGenerationRepository _repository; public async Task StartGenerationAsync(Guid flashcardId, GenerationRequest request) { var generationRequest = await _repository.CreateRequestAsync(flashcardId, request); // 後台執行兩階段生成 _ = Task.Run(() => ExecuteGenerationPipelineAsync(generationRequest)); return new GenerationRequestResult { RequestId = generationRequest.Id, Status = "pending", EstimatedTimeMinutes = 3 }; } private async Task ExecuteGenerationPipelineAsync(ImageGenerationRequest request) { try { // 第一階段:生成圖片描述 await _repository.UpdateStatusAsync(request.Id, "description_generating"); var descriptionResult = await _geminiService.GenerateDescriptionAsync( request.Flashcard, request.Options ); if (!descriptionResult.Success) { await _repository.MarkAsFailedAsync(request.Id, "gemini", descriptionResult.Error); return; } await _repository.UpdateGeminiResultAsync(request.Id, descriptionResult); // 第二階段:生成圖片 await _repository.UpdateStatusAsync(request.Id, "image_generating"); var imageResult = await _replicateService.GenerateImageAsync( descriptionResult.OptimizedPrompt, request.Options.ReplicateModel, request.Options ); if (!imageResult.Success) { await _repository.MarkAsFailedAsync(request.Id, "replicate", imageResult.Error); return; } // 儲存最終結果 var savedImage = await SaveGeneratedImageAsync(imageResult); await _repository.CompleteRequestAsync(request.Id, savedImage.Id); } catch (Exception ex) { _logger.LogError(ex, "Generation pipeline failed for request {RequestId}", request.Id); await _repository.MarkAsFailedAsync(request.Id, "system", ex.Message); } } } ``` #### 6.1.2 品質檢測機制 ```csharp public class ImageQualityValidator { public async Task ValidateAsync(Stream imageStream) { var results = await Task.WhenAll( CheckImageClarity(imageStream), CheckContentAppropriateness(imageStream), CheckEducationalRelevance(imageStream) ); return new QualityResult { OverallScore = results.Average(r => r.Score), Issues = results.SelectMany(r => r.Issues).ToList(), Approved = results.All(r => r.Score >= 0.7) }; } } ``` ### 6.2 儲存服務實現 #### 6.2.1 環境配置 ```json // appsettings.Development.json { "ImageStorage": { "Provider": "Local", "Local": { "BasePath": "wwwroot/images/examples", "BaseUrl": "https://localhost:5001/images/examples", "MaxFileSize": 5242880, // 5MB "AllowedFormats": ["png", "jpg", "webp"] } } } // appsettings.Production.json { "ImageStorage": { "Provider": "AWS", "AWS": { "BucketName": "dramaling-example-images", "Region": "ap-northeast-1", "CDNDomain": "https://cdn.dramaling.com", "AccessKeyId": "{from-environment}", "SecretAccessKey": "{from-environment}" } } } ``` #### 6.2.2 儲存服務實現 ```csharp public class ImageStorageFactory { public static IImageStorageService Create(IConfiguration config, ILogger logger) { var provider = config["ImageStorage:Provider"]; return provider.ToLower() switch { "local" => new LocalImageStorageService(config, logger), "aws" => new AwsImageStorageService(config, logger), "azure" => new AzureImageStorageService(config, logger), _ => throw new NotSupportedException($"Storage provider '{provider}' not supported") }; } } ``` ## 7. 成本控制與優化策略 ### 7.1 兩階段成本結構管理 #### 7.1.1 詳細成本分析 ``` 單次完整生成成本結構: ├── Gemini 描述生成: $0.001 - $0.003 │ ├── 基於輸入 token 數 (~800-1200 tokens,包含詳細規範) │ ├── 輸出 token 數 (~300-500 tokens,詳細描述) │ └── Gemini 1.5 Flash 定價 │ └── Replicate 圖片生成: $0.02 - $0.06 ├── Ideogram V2 Turbo: ~$0.025/張 (主要選擇) ├── FLUX-1-dev: ~$0.05/張 (備選) ├── Stable Diffusion XL: ~$0.04/張 (備選) └── 基於生成時間和運算資源 總成本範圍: $0.021 - $0.063 per 圖片 (使用 Ideogram 約 $0.026) ``` #### 7.1.2 積分系統重新設計 ``` 積分消耗策略 (基於實際成本): ├── Gemini 階段: 0.1 積分 (約 $0.002) ├── Replicate 階段: │ ├── Ideogram V2 Turbo: 2.5 積分 (約 $0.025) - 主要選擇 │ ├── FLUX-1-dev: 5 積分 (約 $0.05) - 高品質選項 │ ├── Stable Diffusion XL: 4 積分 (約 $0.04) - 備選 │ └── 失敗不扣 Replicate 積分 │ └── 總成本: 2.6 - 5.1 積分/張圖片 (Ideogram: 2.6 積分) 用戶等級積分分配: ├── 新用戶: 50 積分 (約 19 張 Ideogram 圖片) ├── 基礎用戶: 250 積分/月 (約 96 張 Ideogram 圖片) ├── 進階用戶: 1000 積分/月 (約 385 張 Ideogram 圖片) └── 企業用戶: 無限制 模型選擇策略: ├── 預設使用 Ideogram V2 Turbo (性價比最佳) ├── 用戶可選擇升級到 FLUX (更高品質) └── 根據用戶積分餘額智能推薦模型 ``` #### 7.1.3 智能成本優化策略 **1. 階段性成本控制** ```csharp public class CostOptimizationStrategy { public async Task ShouldProceedToReplicate(DescriptionResult result, UserQuota quota) { // 檢查用戶剩餘積分是否足夠完成 Replicate 階段 var replicateCost = CalculateReplicateCost(result.Options); if (quota.RemainingCredits < replicateCost) { // Gemini 階段已完成,保存描述供後續使用 await SaveDescriptionForLater(result); return false; } return true; } } ``` **2. 語意去重和共享** - **Gemini 描述快取**:相似詞卡共享描述生成結果 - **最終圖片共享**:完全相同的優化提示詞重用生成結果 - **部分重用策略**:描述相似度 ≥ 85% 時提示用戶選擇重用 **3. 批量和預生成** - **批量 Gemini 調用**:單次請求處理多個詞卡描述 - **預生成熱門詞彙**:基於學習統計預先生成高頻詞彙 - **離峰生成**:成本較低時段優先處理非急迫請求 ### 7.2 兩階段快取策略優化 #### 7.2.1 雙快取架構系統 ``` Gemini 描述快取層: ├── L1: 記憶體快取 (30分鐘) → 最近生成的描述 ├── L2: Redis 快取 (24小時) → 常用詞彙描述 └── L3: 資料庫快取 (永久) → 所有生成的描述 最終圖片快取層: ├── L1: 記憶體快取 (1小時) → 最熱門圖片 URL ├── L2: Redis 快取 (24小時) → 常用圖片 metadata ├── L3: 資料庫快取 (永久) → 所有已生成圖片記錄 └── L4: CDN/儲存快取 (30天) → 實際圖片檔案 ``` #### 7.2.2 智能快取匹配策略 ```csharp public class TwoStageCache { // Gemini 描述快取匹配 public async Task GetCachedDescriptionAsync(Flashcard flashcard, GenerationOptions options) { // 1. 完全匹配:相同詞卡+選項 var exactMatch = await _cache.GetAsync($"desc:{flashcard.Id}:{options.GetHashCode()}"); if (exactMatch != null) return exactMatch; // 2. 語意匹配:相似例句和語境 var semanticMatches = await FindSemanticMatches(flashcard.Example, 0.85); if (semanticMatches.Any()) { return await SelectBestMatch(semanticMatches, options); } // 3. 基礎匹配:同詞不同例句 var wordMatches = await _cache.GetAsync($"desc:word:{flashcard.Word}"); return wordMatches; } // Replicate 圖片快取匹配 public async Task GetCachedImageAsync(string optimizedPrompt) { // 1. 完全匹配:相同的優化提示詞 var promptHash = ComputeHash(optimizedPrompt); var exactImage = await _cache.GetAsync($"img:{promptHash}"); if (exactImage != null) return exactImage; // 2. 相似匹配:相似提示詞 (相似度 ≥ 90%) var similarPrompts = await FindSimilarPrompts(optimizedPrompt, 0.9); if (similarPrompts.Any()) { return await SelectBestImageMatch(similarPrompts); } return null; } } ``` #### 7.2.3 預生成和預快取策略 - **熱門詞彙預生成**:基於學習統計,預先完成兩階段生成 - **描述預生成**:新詞彙預先生成 Gemini 描述,圖片按需生成 - **季節性內容**:節慶、時事相關詞彙的描述和圖片提前準備 - **學習路徑預測**:根據用戶學習進度預生成即將學習的詞彙圖片 ## 8. 監控與分析指標 ### 8.1 關鍵效能指標 (KPIs) #### 8.1.1 生成效能指標 - **生成成功率**:目標 ≥ 95% - **平均生成時間**:目標 ≤ 90 秒 - **圖片品質評分**:目標平均 ≥ 0.85 - **用戶滿意度**:目標 ≥ 4.2/5.0 #### 8.1.2 業務影響指標 - **學習效果提升**:使用例句圖 vs 純文字的記憶測試對比 - **用戶參與度**:有圖片詞卡的複習頻率 vs 無圖片詞卡 - **留存率影響**:使用例句圖功能用戶的留存率提升 - **付費轉換**:例句圖功能對付費訂閱的貢獻度 ### 8.2 實時監控告警 #### 8.2.1 系統健康監控 ```yaml alerts: - name: high_generation_failure_rate condition: failure_rate > 0.1 # 10%失敗率告警 duration: 5m action: slack_notification - name: slow_generation_time condition: avg_generation_time > 120s duration: 3m action: email_alert - name: storage_quota_warning condition: storage_usage > 0.85 # 85%容量告警 action: admin_dashboard_alert ``` ## 9. 開發里程碑與排程 ### 9.1 Phase 1: 兩階段核心功能開發 (5-7 週) #### Week 1-2: 兩階段架構基礎 - [ ] 擴展資料庫 schema (支援兩階段追蹤) - [ ] 實現 `GeminiImageDescriptionService` - [ ] 開發 `ReplicateImageGenerationService` - [ ] 建立 `ImageGenerationOrchestrator` 流程編排 - [ ] 儲存抽象層實現 (本地 + 雲端) #### Week 3-4: API 與後端服務 - [ ] 兩階段生成 API 端點開發 - [ ] 狀態追蹤與進度回報機制 - [ ] 錯誤處理與重試策略 - [ ] Replicate API 整合與輪詢機制 - [ ] 基於現有 Gemini 服務的描述生成 #### Week 5-6: 前端整合與用戶體驗 - [ ] 詞卡頁面新增兩階段生成功能 - [ ] 分階段載入狀態與進度顯示 - [ ] 實時狀態更新 (WebSocket/長輪詢) - [ ] 兩階段錯誤處理與用戶回饋 - [ ] 響應式設計適配 #### Week 7: 快取與優化 - [ ] 兩階段快取機制實現 - [ ] Gemini 描述語意匹配 - [ ] Replicate 圖片去重機制 - [ ] 批量處理佇列開發 - [ ] 成本控制策略實現 ### 9.2 Phase 2: 進階功能與成本優化 (3-4 週) #### Week 8-9: 智能優化與成本控制 - [ ] 階段性積分扣款系統 - [ ] 智能提示詞優化引擎 (Gemini→Replicate) - [ ] 相似性檢測與快取共享 - [ ] 預生成策略 (熱門詞彙描述) - [ ] 圖片品質自動評分 #### Week 10-11: 管理功能與監控 - [ ] 兩階段成本統計與報表 - [ ] 管理後台 (Gemini 描述審核 + 圖片審核) - [ ] 用戶積分系統整合 - [ ] 分階段監控告警 (Gemini 失敗率、Replicate 超時) - [ ] 效能分析儀表板 ### 9.3 Phase 3: 生產部署與擴展 (2-3 週) #### Week 12-13: 生產環境部署 - [ ] Replicate API 生產環境配置 - [ ] 雲端儲存服務配置與 CDN - [ ] 兩階段生成的容錯與降級機制 - [ ] 生產環境部署測試 - [ ] 灰度發布 (先開放描述生成,再開放圖片生成) #### Week 14: 優化與擴展 - [ ] 用戶回饋收集與兩階段效果分析 - [ ] 成本效益分析與積分系統調優 - [ ] 多模型支援擴展 (更多 Replicate 模型) - [ ] 文檔完善與團隊培訓 ### 9.4 技術風險時程調整 #### 高風險項目緩衝時間 - **Replicate API 整合複雜度**: +1 週 - **兩階段狀態同步機制**: +0.5 週 - **成本控制策略實現**: +0.5 週 - **快取匹配算法優化**: +1 週 #### 總預估時程: **10-14 週** - **最樂觀**: 10 週 (無重大技術障礙) - **實際預估**: 12 週 (包含常見問題處理) - **保守估計**: 14 週 (包含風險緩衝) ## 10. 風險評估與應對策略 ### 10.1 技術風險 #### 10.1.1 AI 服務依賴風險 - **風險**:第三方 AI 服務中斷或限制 - **機率**:中等 - **影響**:高 - **應對策略**: - 多供應商備援 (DALL-E 3 + Midjourney + Stable Diffusion) - 離線 fallback 機制 (預設圖片庫) - 服務降級策略 (優雅處理失敗) #### 10.1.2 儲存成本失控風險 - **風險**:圖片儲存成本超出預算 - **機率**:低 - **影響**:中等 - **應對策略**: - 自動清理未使用圖片機制 - 壓縮與格式優化 (WebP) - 儲存層級管理 (熱/溫/冷數據分層) ### 10.2 產品風險 #### 10.2.1 用戶接受度風險 - **風險**:用戶對 AI 生成圖片品質不滿意 - **機率**:中等 - **影響**:中等 - **應對策略**: - 提供手動上傳選項 - 多候選圖片讓用戶選擇 - 持續的品質改進機制 #### 10.2.2 內容合規風險 - **風險**:AI 生成不當內容 - **機率**:低 - **影響**:高 - **應對策略**: - 多層內容過濾機制 - 人工審核流程 - 用戶舉報與快速處理機制 ## 11. 成功指標與驗證方式 ### 11.1 量化成功指標 #### 11.1.1 技術指標 - 圖片生成成功率 ≥ 95% - 平均生成時間 ≤ 90 秒 - 系統可用性 ≥ 99.5% - 圖片載入速度 ≤ 2 秒 #### 11.1.2 業務指標 - 用戶對圖片品質滿意度 ≥ 4.2/5.0 - 使用例句圖功能的詞卡複習率提升 ≥ 30% - 用戶留存率提升 ≥ 15% - 功能使用率 ≥ 60% (活躍用戶中) ### 11.2 驗證方式 #### 11.2.1 A/B 測試設計 - **測試組 A**:使用例句圖功能的用戶 - **對照組 B**:僅使用文字例句的用戶 - **測試指標**:學習效果、用戶參與度、留存率 - **測試週期**:4-6 週 #### 11.2.2 用戶回饋收集 - 功能滿意度問卷調查 - 用戶訪談與深度回饋 - 應用商店評分變化追蹤 - 客服反饋問題分析 --- ## 文檔版本資訊 - **版本**:v1.0 - **創建日期**:2025-09-24 - **最後更新**:2025-09-24 - **負責人**:產品開發團隊 - **審核狀態**:待審核 --- *本文檔將隨著開發進展持續更新,確保與實際實現保持同步。如有疑問或建議,請聯繫產品團隊。*