import { HoverCard, HoverCardContent, HoverCardTrigger, } from '@radix-ui/react-hover-card' import { Check, Copy, FileIcon, XCircleIcon } from 'lucide-react' import { useCopyToClipboard } from '../hook/use-copy-to-clipboard' import { Button } from '../ui/button' import { PdfDialog } from './pdf-dialog' import { SourceNumberButton } from './source-number-button' import { cn } from '../lib/utils' import { DocxIcon } from '../ui/icons/docx' import { PDFIcon } from '../ui/icons/pdf' import { SheetIcon } from '../ui/icons/sheet' import { TxtIcon } from '../ui/icons/txt' import { JSONValue } from '../chat/chat.interface' export type DocumentFile = { id: string name: string // The uploaded file name in the backend size: number // The file size in bytes type: string // File extension url: string // The URL of the uploaded file in the backend refs?: string[] // DocumentIDs of the uploaded file in the vector index } export type SourceNode = { id: string metadata: Record score?: number text: string url?: string } export type Document = { url: string sources: SourceNode[] } export function DocumentInfo({ document, className, onRemove, startIndex = 0, }: { document: Document className?: string onRemove?: () => void startIndex?: number }) { const { url, sources } = document const urlParts = url.split('/') const fileName = urlParts.length > 0 ? urlParts[urlParts.length - 1] : url const fileExt = fileName?.split('.').pop() ?? '' const previewFile = { name: fileName, type: fileExt, } const DocumentDetail = (
{sources.map((node: SourceNode, index: number) => (
))}
) if (url.endsWith('.pdf')) { // open internal pdf dialog for pdf files when click document card return } // open external link when click document card for other file types return
window.open(url, '_blank')}>{DocumentDetail}
} function SourceInfo({ node, index }: { node?: SourceNode; index: number }) { if (!node) return return ( { e.preventDefault() e.stopPropagation() }} > ) } function NodeInfo({ nodeInfo }: { nodeInfo: SourceNode }) { const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 1000 }) const pageNumber = // XXX: page_label is used in Python, but page_number is used by Typescript (nodeInfo.metadata?.page_number as number) ?? (nodeInfo.metadata?.page_label as number) ?? null return (
{pageNumber ? `On page ${pageNumber}:` : 'Node content:'} {nodeInfo.text && ( )}
{nodeInfo.text && (
          “{nodeInfo.text}”
        
)}
) } const FileIconMap: Record = { csv: , pdf: , docx: , txt: , } function DocumentPreviewCard(props: { file: { name: string size?: number type: string } onRemove?: () => void className?: string }) { const { onRemove, file, className } = props return (
{FileIconMap[file.type] ?? }
{file.name} {file.size ? `(${inKB(file.size)} KB)` : ''}
{file.type && (
{file.type.toUpperCase()} File
)}
{onRemove && (
{ e.stopPropagation() onRemove() }} />
)}
) } function inKB(size: number) { return Math.round((size / 1024) * 10) / 10 }