初始化模版工程
This commit is contained in:
117
components/nova-sdk/hooks/useArtifactsExtractor.ts
Normal file
117
components/nova-sdk/hooks/useArtifactsExtractor.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
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])
|
||||
}
|
||||
Reference in New Issue
Block a user