import { useMemo } from 'react' import type { ApiEvent } from '../types' import type { TaskArtifact, TaskStatus } from '../types' import { TaskStatus as Status } from '../types' /** * 从事件中提取 artifacts 和 taskStatus */ export function useArtifactsExtractor(rawEvents: ApiEvent[]) { return useMemo(() => { const extractedArtifacts: TaskArtifact[] = [] const artifactKeys = new Set() // 用于去重 let status: TaskStatus = Status.PENDING for (const event of rawEvents) { const content = event.content as Record | undefined const isUserInput = event.event_type === 'user_input' || event.role === 'user' if (!content) continue // 1. 提取 attachments if (content.attachments) { const attachments = Array.isArray(content.attachments) ? content.attachments : [content.attachments] for (const att of attachments) { if (att?.file_name) { const key = att.file_url || att.file_id || att.path || att.file_name if (!artifactKeys.has(key)) { artifactKeys.add(key) extractedArtifacts.push({ path: att.path || att.file_url || att.file_id || '', file_name: att.file_name, file_type: att.file_type || att.file_name.split('.').pop() || '', url: att.file_url, from: isUserInput ? 'user' : 'assistant' }) } } } } // 2. 提取 attachment_files if (content.attachment_files && Array.isArray(content.attachment_files)) { for (const file of content.attachment_files) { if (file?.file_name) { const key = file.url || file.path || file.file_name if (!artifactKeys.has(key)) { artifactKeys.add(key) extractedArtifacts.push({ path: file.path || file.url || '', file_name: file.file_name, file_type: file.file_type || file.file_name.split('.').pop() || '', url: file.url, from: isUserInput ? 'user' : 'assistant' }) } } } } // 3. 提取 generated_files (如 slide_create_in_batches 的输出) const toolOutput = content.tool_output as Record | undefined if (toolOutput?.generated_files && Array.isArray(toolOutput.generated_files)) { for (const file of toolOutput.generated_files) { if (file?.index !== undefined && file?.content) { const fileName = `slide_${file.index}.html` const key = `generated_${event.event_id}_${file.index}` if (!artifactKeys.has(key)) { artifactKeys.add(key) extractedArtifacts.push({ path: key, file_name: fileName, file_type: 'html', event_type: 'generated_file', tool_output: file.content, from: isUserInput ? 'user' : 'assistant' }) } } } } // 4. 提取 files (其他可能的文件字段) if (content.files && Array.isArray(content.files)) { for (const file of content.files) { if (file?.name || file?.file_name) { const fileName = file.name || file.file_name const key = file.url || file.path || file.id || fileName if (!artifactKeys.has(key)) { artifactKeys.add(key) extractedArtifacts.push({ path: file.path || file.url || file.id || '', file_name: fileName, file_type: file.type || file.file_type || fileName.split('.').pop() || '', url: file.url, from: isUserInput ? 'user' : 'assistant' }) } } } } // 提取 taskStatus const eventStatus = event.event_status as string | undefined if (eventStatus === 'running' || eventStatus === 'in_progress') { status = Status.IN_PROGRESS } else if (eventStatus === 'success' || eventStatus === 'completed') { status = Status.COMPLETED } else if (eventStatus === 'failed' || eventStatus === 'error') { status = Status.FAILED } } return { artifacts: extractedArtifacts, taskStatus: status } }, [rawEvents]) }