118 lines
4.3 KiB
TypeScript
118 lines
4.3 KiB
TypeScript
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<string>() // 用于去重
|
|
let status: TaskStatus = Status.PENDING
|
|
|
|
for (const event of rawEvents) {
|
|
const content = event.content as Record<string, unknown> | 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<string, unknown> | 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])
|
|
}
|