/** * AI 故事分析 Composable * 用於分析故事並提取資產 */ import { useAIProvider } from './useAIProvider' import { buildStoryAnalysisPrompt, type StoryAnalysisInput } from '~/utils/ai/prompts' import { getTextModel } from '~/utils/storage' import { DEFAULT_TEXT_MODEL } from '~/utils/clients/gemini-models' import { getVisionModel } from '~/utils/storage' import { DEFAULT_VISION_MODEL } from '~/utils/clients/gemini-models' import type { StoryAnalysis } from '~/types/storyboard' export function useAIStoryboardAnalysis() { const isLoading = ref(false) const error = ref(null) async function analyze(input: StoryAnalysisInput): Promise { isLoading.value = true error.value = null try { // 如果有圖片,使用視覺模型;否則使用文字模型 const modelName = input.styleImage ? (getVisionModel() || DEFAULT_VISION_MODEL) : (getTextModel() || DEFAULT_TEXT_MODEL) const provider = useAIProvider(modelName) let prompt = buildStoryAnalysisPrompt(input) // 如果有風格圖片,需要傳遞圖片給 API if (input.styleImage) { // 這裡需要根據 provider 類型處理圖片 // 暫時先傳遞文字 prompt,實際實作時需要處理圖片 const result = await provider.analyzeCamera({ prompt, image: { mimeType: 'image/jpeg', data: input.styleImage.replace(/^data:image\/\w+;base64,/, '') } }) // 解析 JSON 結果 const jsonMatch = result.match(/\{[\s\S]*\}/) if (jsonMatch) { return JSON.parse(jsonMatch[0]) as StoryAnalysis } throw new Error('無法解析分析結果') } else { const result = await provider.generateStoryboard(prompt) // 解析 JSON 結果 const jsonMatch = result.match(/\{[\s\S]*\}/) if (jsonMatch) { return JSON.parse(jsonMatch[0]) as StoryAnalysis } throw new Error('無法解析分析結果') } } catch (err) { const errorMessage = err instanceof Error ? err.message : '未知錯誤' error.value = errorMessage throw err } finally { isLoading.value = false } } return { analyze, isLoading: readonly(isLoading), error: readonly(error) } }