dramaling-vocab-learning/frontend/hooks/flashcards/useFlashcardImageGeneration.ts

92 lines
3.1 KiB
TypeScript

import { useState } from 'react'
import { imageGenerationService } from '@/lib/services/imageGeneration'
import { useToast } from '@/components/shared/Toast'
import type { Flashcard } from '@/lib/services/flashcards'
interface UseFlashcardImageGenerationReturn {
generatingCards: Set<string>
generationProgress: { [cardId: string]: string }
generateImage: (card: Flashcard, onComplete?: () => void) => Promise<void>
}
export const useFlashcardImageGeneration = (): UseFlashcardImageGenerationReturn => {
const toast = useToast()
const [generatingCards, setGeneratingCards] = useState<Set<string>>(new Set())
const [generationProgress, setGenerationProgress] = useState<{ [cardId: string]: string }>({})
const generateImage = async (card: Flashcard, onComplete?: () => void) => {
try {
// 檢查是否已在生成中
if (generatingCards.has(card.id)) {
toast.error('該詞卡正在生成圖片中,請稍候...')
return
}
// 標記為生成中
setGeneratingCards(prev => new Set([...prev, card.id]))
setGenerationProgress(prev => ({ ...prev, [card.id]: '啟動生成中...' }))
toast.info(`開始為「${card.word}」生成例句圖片...`)
// 1. 啟動圖片生成
const generateResult = await imageGenerationService.generateImage(card.id)
if (!generateResult.success || !generateResult.data) {
throw new Error(generateResult.error || '啟動生成失敗')
}
const requestId = generateResult.data.requestId
setGenerationProgress(prev => ({ ...prev, [card.id]: 'Gemini 生成描述中...' }))
// 2. 輪詢生成進度
const finalStatus = await imageGenerationService.pollUntilComplete(
requestId,
(status) => {
// 更新進度顯示
const stage = status.stages.gemini.status === 'completed'
? 'Replicate 生成圖片中...'
: 'Gemini 生成描述中...'
setGenerationProgress(prev => ({ ...prev, [card.id]: stage }))
},
5 // 5分鐘超時
)
// 3. 生成成功,刷新資料
if (finalStatus.overallStatus === 'completed') {
setGenerationProgress(prev => ({ ...prev, [card.id]: '生成完成,載入中...' }))
// 通知父組件刷新數據
if (onComplete) {
await onComplete()
}
toast.success(`${card.word}」的例句圖片生成完成!`)
} else {
throw new Error('圖片生成未完成')
}
} catch (error: any) {
console.error('圖片生成失敗:', error)
toast.error(`圖片生成失敗: ${error.message || '未知錯誤'}`)
} finally {
// 清理狀態
setGeneratingCards(prev => {
const newSet = new Set(prev)
newSet.delete(card.id)
return newSet
})
setGenerationProgress(prev => {
const newProgress = { ...prev }
delete newProgress[card.id]
return newProgress
})
}
}
return {
generatingCards,
generationProgress,
generateImage
}
}