import React from 'react' import { cn } from '@/utils/cn' import type { ImageAttachment, TaskArtifact } from '../../types' import { useNovaKit } from '../../context/useNovaKit' import { isImageFile } from '../utils' import { TaskArtifactHtml } from '@/components/html-editor' import { Html } from '@/components/html-editor/components/html-render/task-html' import PptPreview from '@/components/ppt-editor' import { ImageAttachmentItem } from '../../message-list/message-item/ImageAttachmentItem' import { UrlScriptPreview } from './UrlScriptPreview' import { ShellExecutePreview } from './ShellExecutePreview' import { MarkdownContent, MarkdownPreview } from './MarkdownPreview' import { CsvPreview } from './CsvPreview' import { VirtualPdfPreview } from './VirtualPdfPreview' import { isScriptLikeFile, normalizeArtifactFileType } from './previewUtils' export interface ToolOutputArtifactPreviewProps { artifact: TaskArtifact className?: string } const PREVIEW_FILE_TYPES = ['xlsx', 'xls', 'doc', 'docx'] const TEXT_LIKE_FILE_TYPES = ['txt', 'text', 'json', 'log', 'xml', 'yaml', 'yml'] export function ToolOutputArtifactPreview({ artifact, className, }: ToolOutputArtifactPreviewProps) { const { api, conversationId, mode } = useNovaKit() const [url, setUrl] = React.useState('') const [isUrlLoading, setIsUrlLoading] = React.useState(false) const editable = mode === 'chat' const normalizedFileType = normalizeArtifactFileType( artifact.file_type, artifact.file_name, artifact.path, ) React.useEffect(() => { const directUrl = artifact.url || (/^https?:\/\//.test(artifact.path) ? artifact.path : '') if (directUrl) { setUrl(directUrl) setIsUrlLoading(false) return } if (artifact.path) { setIsUrlLoading(true) setUrl('') api .getArtifactUrl?.( artifact, PREVIEW_FILE_TYPES.includes(normalizedFileType) ? { 'x-oss-process': 'doc/preview,print_1,copy_1,export_1', } : undefined, ) .then(res => { const originUrl = typeof res?.data === 'string' ? res.data : '' if (PREVIEW_FILE_TYPES.includes(normalizedFileType)) { const shortUrl = originUrl.replace( 'oss-cn-hangzhou.aliyuncs.com', 'betteryeah.com', ) setUrl( shortUrl ? `${shortUrl}&x-oss-process=doc%2Fpreview%2Cprint_1%2Ccopy_1%2Cexport_1` : '', ) } else { setUrl(originUrl) } setIsUrlLoading(false) }) .catch(() => { setIsUrlLoading(false) }) return } setIsUrlLoading(false) // eslint-disable-next-line react-hooks/exhaustive-deps }, [artifact.path, artifact.url, normalizedFileType]) const isImage = isImageFile(artifact.path) || isImageFile(artifact.file_name) || ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp'].includes(normalizedFileType) if (isImage) { const imageAttachment: ImageAttachment = { url: artifact.url || '', path: artifact.path, file_name: artifact.file_name, file_url: artifact.url, } return (
) } const isHtml = normalizedFileType === 'html' || artifact.file_name?.toLowerCase().endsWith('.html') if (isHtml && artifact.content && !artifact.path) { return } if (isHtml) { return (
) } const isMarkdown = normalizedFileType === 'md' || normalizedFileType === 'markdown' || artifact.file_name?.toLowerCase().endsWith('.md') if (isMarkdown && url) { return
} if (isMarkdown && artifact.content) { return (
) } const isPpt = normalizedFileType === 'ppt' || normalizedFileType === 'pptx' || artifact.file_name?.toLowerCase().endsWith('.ppt') || artifact.file_name?.toLowerCase().endsWith('.pptx') if (isPpt && url) { return (
) } const isCsv = normalizedFileType === 'csv' || artifact.file_name?.toLowerCase().endsWith('.csv') if (isCsv && artifact.content) { return
} if (isCsv && url) { return
} const isPdf = normalizedFileType === 'pdf' || artifact.file_name?.toLowerCase().endsWith('.pdf') if (isPdf && url) { return
} const isScript = isScriptLikeFile(artifact) if (isScript && artifact.content) { return (
) } const isTextLike = TEXT_LIKE_FILE_TYPES.includes(normalizedFileType) if (isTextLike && artifact.content) { return (
) } if ((isScript || isTextLike) && url) { return
} if (url) { return (