import { DeleteOutlined, EditOutlined, FileTextOutlined, FolderOutlined, GlobalOutlined, LinkOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons' import PromptPopup from '@renderer/components/Popups/PromptPopup' import TextEditPopup from '@renderer/components/Popups/TextEditPopup' import Scrollbar from '@renderer/components/Scrollbar' import { useKnowledge } from '@renderer/hooks/useKnowledge' import FileManager from '@renderer/services/FileManager' import { FileType, FileTypes, KnowledgeBase } from '@renderer/types' import { Alert, Button, Card, Divider, message, Tag, Typography, Upload } from 'antd' import { FC } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' import KnowledgeSearchPopup from './components/KnowledgeSearchPopup' import StatusIcon from './components/StatusIcon' const { Dragger } = Upload const { Title } = Typography interface KnowledgeContentProps { selectedBase: KnowledgeBase } const fileTypes = ['.pdf', '.docx', '.pptx', '.xlsx', '.txt', '.md', '.mdx'] const FlexColumn = styled.div` display: flex; flex-direction: column; gap: 8px; ` const FlexAlignCenter = styled.div` display: flex; align-items: center; gap: 16px; ` const ClickableSpan = styled.span` cursor: pointer; ` const FileIcon = styled(FileTextOutlined)` font-size: 16px; ` const BottomSpacer = styled.div` min-height: 20px; ` const KnowledgeContent: FC = ({ selectedBase }) => { const { t } = useTranslation() const { base, noteItems, fileItems, urlItems, sitemapItems, directoryItems, addFiles, updateNoteContent, addUrl, addSitemap, removeItem, getProcessingStatus, addNote, addDirectory } = useKnowledge(selectedBase.id || '') if (!base) { return null } const handleAddFile = () => { const input = document.createElement('input') input.type = 'file' input.multiple = true input.accept = fileTypes.join(',') input.onchange = (e) => { const files = (e.target as HTMLInputElement).files files && handleDrop(Array.from(files)) } input.click() } const handleDrop = async (files: File[]) => { if (files) { const _files: FileType[] = files.map((file) => ({ id: file.name, name: file.name, path: file.path, size: file.size, ext: `.${file.name.split('.').pop()}`, count: 1, origin_name: file.name, type: file.type as FileTypes, created_at: new Date() })) console.debug('[KnowledgeContent] Uploading files:', _files, files) const uploadedFiles = await FileManager.uploadFiles(_files) addFiles(uploadedFiles) } } const handleAddUrl = async () => { const url = await PromptPopup.show({ title: t('knowledge_base.add_url'), message: '', inputPlaceholder: t('knowledge_base.url_placeholder'), inputProps: { maxLength: 1000, rows: 1 } }) if (url) { try { new URL(url) if (urlItems.find((item) => item.content === url)) { message.success(t('knowledge_base.url_added')) return } addUrl(url) } catch (e) { console.error('Invalid URL:', url) } } } const handleAddSitemap = async () => { const url = await PromptPopup.show({ title: t('knowledge_base.add_sitemap'), message: '', inputPlaceholder: t('knowledge_base.sitemap_placeholder'), inputProps: { maxLength: 1000, rows: 1 } }) if (url) { try { new URL(url) if (sitemapItems.find((item) => item.content === url)) { message.success(t('knowledge_base.sitemap_added')) return } addSitemap(url) } catch (e) { console.error('Invalid Sitemap URL:', url) } } } const handleAddNote = async () => { const note = await TextEditPopup.show({ text: '', textareaProps: { rows: 20 } }) note && addNote(note) } const handleEditNote = async (note: any) => { const editedText = await TextEditPopup.show({ text: note.content as string, textareaProps: { rows: 20 } }) editedText && updateNoteContent(note.id, editedText) } const handleAddDirectory = async () => { const path = await window.api.file.selectFolder() console.log('[KnowledgeContent] Selected directory:', path) path && addDirectory(path) } return ( {!base.dimensions && ( )} {t('files.title')} handleDrop([file as File])} multiple={true} accept={fileTypes.join(',')} style={{ marginTop: 10, background: 'transparent' }}>

{t('knowledge_base.drag_file')}

{t('knowledge_base.file_hint', { file_types: fileTypes.join(', ').replaceAll('.', '') })}

{fileItems.map((item) => { const file = item.content as FileType return ( window.api.file.openPath(file.path)}>{file.origin_name} {directoryItems.map((item) => ( window.api.file.openPath(item.content as string)}> {item.content as string} {urlItems.map((item) => ( {item.content as string} {sitemapItems.map((item) => ( {item.content as string} {noteItems.map((note) => ( handleEditNote(note)} style={{ cursor: 'pointer' }}> {(note.content as string).slice(0, 50)}...
) } const MainContent = styled(Scrollbar)` display: flex; width: 100%; flex-direction: column; padding-bottom: 50px; padding: 15px; position: relative; ` const FileSection = styled.div` display: flex; flex-direction: column; ` const ContentSection = styled.div` margin-top: 20px; display: flex; flex-direction: column; gap: 10px; .ant-input-textarea { background: var(--color-background-soft); border-radius: 8px; } ` const TitleWrapper = styled.div` display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; background-color: var(--color-background-soft); padding: 5px 20px; min-height: 45px; border-radius: 6px; .ant-typography { margin-bottom: 0; } ` const FileListSection = styled.div` margin-top: 20px; width: 100%; display: flex; flex-direction: column; gap: 8px; ` const ItemCard = styled(Card)` background-color: transparent; border: none; .ant-card-body { padding: 0 20px; } ` const ItemContent = styled.div` display: flex; align-items: center; justify-content: space-between; gap: 16px; ` const ItemInfo = styled.div` display: flex; align-items: center; gap: 8px; flex: 1; a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 600px; } ` const IndexSection = styled.div` margin-top: 20px; display: flex; justify-content: center; ` const ModelInfo = styled.div` display: flex; align-items: center; padding: 5px; color: var(--color-text-3); label { margin-right: 8px; color: var(--color-text-2); } ` export default KnowledgeContent