diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index 76e0960..ebb3f88 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -27,6 +27,7 @@ import { selectConversationId, selectModalStateDeleteConv, setModalStateDeleteConv, + setSourceDocs, } from './preferences/preferenceSlice'; import { setConversation, @@ -34,7 +35,7 @@ import { } from './conversation/conversationSlice'; import { useMediaQuery, useOutsideAlerter } from './hooks'; import Upload from './upload/Upload'; -import { Doc, getConversations } from './preferences/preferenceApi'; +import { Doc, getConversations, getDocs } from './preferences/preferenceApi'; import SelectDocsModal from './preferences/SelectDocsModal'; import ConversationTile from './conversation/ConversationTile'; import { useDarkTheme } from './hooks'; @@ -124,19 +125,29 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { .catch((error) => console.error(error)); }; - const handleDeleteClick = (index: number, doc: Doc) => { - const docPath = 'indexes/' + 'local' + '/' + doc.name; + const handleDeleteClick = (doc: Doc) => { + const docPath = `indexes/local/${doc.name}`; fetch(`${apiHost}/api/delete_old?path=${docPath}`, { method: 'GET', }) .then(() => { // remove the image element from the DOM - const imageElement = document.querySelector( - `#img-${index}`, - ) as HTMLElement; - const parentElement = imageElement.parentNode as HTMLElement; - parentElement.parentNode?.removeChild(parentElement); + // const imageElement = document.querySelector( + // `#img-${index}`, + // ) as HTMLElement; + // const parentElement = imageElement.parentNode as HTMLElement; + // parentElement.parentNode?.removeChild(parentElement); + + return getDocs(); + }) + .then((updatedDocs) => { + dispatch(setSourceDocs(updatedDocs)); + dispatch( + setSelectedDocs( + updatedDocs?.find((doc) => doc.name.toLowerCase() === 'default'), + ), + ); }) .catch((error) => console.error(error)); }; diff --git a/frontend/src/components/SourceDropdown.tsx b/frontend/src/components/SourceDropdown.tsx index ec0f1fc..af85026 100644 --- a/frontend/src/components/SourceDropdown.tsx +++ b/frontend/src/components/SourceDropdown.tsx @@ -90,7 +90,7 @@ function SourceDropdown({ id={`img-${index}`} onClick={(event) => { event.stopPropagation(); - handleDeleteClick(index, option); + handleDeleteClick(option); }} /> )} diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 9555682..f686ea2 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -1,109 +1,108 @@ { - "language": "普通话", - "chat": "聊天", - "chats": "聊天", - "newChat": "新聊天", - "myPlan": "我的计划", - "about": "关于", - "inputPlaceholder": "在这里输入您的消息...", - "tagline": "DocsGPT 使用 GenAI, 请使用来源审核关键信息.", - "sourceDocs": "来源文档", - "none": "无", - "cancel":"取消", - "demo": [ - { - "header": "了解 DocsGPT", - "query": "DocsGPT 是什么" - }, - { - "header": "总结文档", - "query": "总结当前情况" - }, - { - "header": "编写代码", - "query": "为 /api/answer API 请求编写代码" - }, - { - "header": "学习帮助", - "query": "为背景写出潜在问题" - } - ], - "settings": { - "label": "设置", - "general": { - "label": "般", - "selectTheme": "选择主题", - "light": "浅色", - "dark": "暗色", - "selectLanguage": "选择语言", - "chunks": "每个查询处理的块", - "prompt": "提示", - "deleteAllLabel": "删除所有对话", - "deleteAllBtn": "删除所有", - "addNew": "添加新的", - "convHistory":"对话历史", - "none":"无", - "low":"低", - "medium":"中", - "high":"高", - "unlimited":"无限", - "default":"默认" - }, - "documents": { - "label": "文件", - "name": "文件名称", - "date": "向量日期", - "type": "类型", - "tokenUsage": "令牌使用" - }, - "apiKeys": { - "label": "API 密钥", - "name": "名称", - "key": "API 密钥", - "sourceDoc": "源文档", - "createNew": "创建新的" - } + "language": "普通话", + "chat": "聊天", + "chats": "聊天", + "newChat": "新聊天", + "myPlan": "我的计划", + "about": "关于", + "inputPlaceholder": "在这里输入您的消息...", + "tagline": "DocsGPT 使用 GenAI, 请使用来源审核关键信息.", + "sourceDocs": "来源文档", + "none": "无", + "cancel": "取消", + "demo": [ + { + "header": "了解 DocsGPT", + "query": "DocsGPT 是什么" + }, + { + "header": "总结文档", + "query": "总结当前情况" + }, + { + "header": "编写代码", + "query": "为 /api/answer API 请求编写代码" + }, + { + "header": "学习帮助", + "query": "为背景写出潜在问题" + } + ], + "settings": { + "label": "设置", + "general": { + "label": "般", + "selectTheme": "选择主题", + "light": "浅色", + "dark": "暗色", + "selectLanguage": "选择语言", + "chunks": "每个查询处理的块", + "prompt": "提示", + "deleteAllLabel": "删除所有对话", + "deleteAllBtn": "删除所有", + "addNew": "添加新的", + "convHistory": "对话历史", + "none": "无", + "low": "低", + "medium": "中", + "high": "高", + "unlimited": "无限", + "default": "默认" }, - "modals": { - "uploadDoc": { - "label": "上传新文档资料", - "file": "从文件", - "remote": "远程", - "name": "名称", - "choose": "选择文件", - "info": "请上传 .pdf, .txt, .rst, .docx, .md, .zip 文件,限 25MB", - "uploadedFiles": "已上传文件", - "cancel": "取消", - "train": "训练", - "link": "链接", - "urlLink": "URL 链接", - "reddit": { - "id": "客户端 ID", - "secret": "客户端密钥", - "agent": "用户代理", - "searchQueries": "搜索查询", - "numberOfPosts": "帖子数量" - } - }, - "createAPIKey": { - "label": "创建新的 API 密钥", - "apiKeyName": "API 密钥名称", - "chunks": "每个查询处理的块", - "prompt": "选择活动提示", - "sourceDoc": "源文档", - "create": "创建" - }, - "saveKey": { - "note": "请保存您的密钥", - "disclaimer": "这是您的密钥唯一一次展示机会。", - "copy": "复制", - "copied": "已复制", - "confirm": "我已保存密钥" - }, - "deleteConv": { - "confirm": "您确定要删除所有对话吗?", - "delete": "删除" + "documents": { + "label": "文件", + "name": "文件名称", + "date": "向量日期", + "type": "类型", + "tokenUsage": "令牌使用" + }, + "apiKeys": { + "label": "API 密钥", + "name": "名称", + "key": "API 密钥", + "sourceDoc": "源文档", + "createNew": "创建新的" + } + }, + "modals": { + "uploadDoc": { + "label": "上传新文档资料", + "file": "从文件", + "remote": "远程", + "name": "名称", + "choose": "选择文件", + "info": "请上传 .pdf, .txt, .rst, .docx, .md, .zip 文件,限 25MB", + "uploadedFiles": "已上传文件", + "cancel": "取消", + "train": "训练", + "link": "链接", + "urlLink": "URL 链接", + "reddit": { + "id": "客户端 ID", + "secret": "客户端密钥", + "agent": "用户代理", + "searchQueries": "搜索查询", + "numberOfPosts": "帖子数量" } + }, + "createAPIKey": { + "label": "创建新的 API 密钥", + "apiKeyName": "API 密钥名称", + "chunks": "每个查询处理的块", + "prompt": "选择活动提示", + "sourceDoc": "源文档", + "create": "创建" + }, + "saveKey": { + "note": "请保存您的密钥", + "disclaimer": "这是您的密钥唯一一次展示机会。", + "copy": "复制", + "copied": "已复制", + "confirm": "我已保存密钥" + }, + "deleteConv": { + "confirm": "您确定要删除所有对话吗?", + "delete": "删除" } } - \ No newline at end of file +} diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index 6437acc..7b426e1 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -4,10 +4,11 @@ import { useDropzone } from 'react-dropzone'; import { useDispatch } from 'react-redux'; import { ActiveState } from '../models/misc'; import { getDocs } from '../preferences/preferenceApi'; -import { setSourceDocs } from '../preferences/preferenceSlice'; +import { setSelectedDocs, setSourceDocs } from '../preferences/preferenceSlice'; import Dropdown from '../components/Dropdown'; import { useTranslation } from 'react-i18next'; -export default function Upload({ + +function Upload({ modalState, setModalState, }: { @@ -24,25 +25,28 @@ export default function Upload({ search_queries: [''], number_posts: 10, }); + const [activeTab, setActiveTab] = useState('file'); + const [files, setfiles] = useState([]); + const [progress, setProgress] = useState<{ + type: 'UPLOAD' | 'TRAINIING'; + percentage: number; + taskId?: string; + failed?: boolean; + }>(); + const { t } = useTranslation(); + const urlOptions: { label: string; value: string }[] = [ { label: 'Crawler', value: 'crawler' }, // { label: 'Sitemap', value: 'sitemap' }, { label: 'Link', value: 'url' }, { label: 'Reddit', value: 'reddit' }, ]; + const [urlType, setUrlType] = useState<{ label: string; value: string }>({ label: 'Link', value: 'url', }); - const [activeTab, setActiveTab] = useState('file'); - const [files, setfiles] = useState([]); - const [progress, setProgress] = useState<{ - type: 'UPLOAD' | 'TRAINIING'; - percentage: number; - taskId?: string; - failed?: boolean; - }>(); function Progress({ title, @@ -93,16 +97,26 @@ export default function Upload({ function TrainingProgress() { const dispatch = useDispatch(); + useEffect(() => { - (progress?.percentage ?? 0) < 100 && - setTimeout(() => { + let timeoutID: number | undefined; + + if ((progress?.percentage ?? 0) < 100) { + timeoutID = setTimeout(() => { const apiHost = import.meta.env.VITE_API_HOST; fetch(`${apiHost}/api/task_status?task_id=${progress?.taskId}`) .then((data) => data.json()) .then((data) => { if (data.status == 'SUCCESS') { if (data.result.limited === true) { - getDocs().then((data) => dispatch(setSourceDocs(data))); + getDocs().then((data) => { + dispatch(setSourceDocs(data)); + dispatch( + setSelectedDocs( + data?.find((d) => d.location.toLowerCase() === 'local'), + ), + ); + }); setProgress( (progress) => progress && { @@ -112,7 +126,14 @@ export default function Upload({ }, ); } else { - getDocs().then((data) => dispatch(setSourceDocs(data))); + getDocs().then((data) => { + dispatch(setSourceDocs(data)); + dispatch( + setSelectedDocs( + data?.find((d) => d.location.toLowerCase() === 'local'), + ), + ); + }); setProgress( (progress) => progress && { @@ -133,6 +154,14 @@ export default function Upload({ } }); }, 5000); + } + + // cleanup + return () => { + if (timeoutID !== undefined) { + clearTimeout(timeoutID); + } + }; }, [progress, dispatch]); return ( ) => { const { name, value } = e.target; if (name === 'search_queries' && value.length > 0) { @@ -230,7 +260,9 @@ export default function Upload({ [name]: value, }); }; + let view; + if (progress?.type === 'UPLOAD') { view = ; } else if (progress?.type === 'TRAINIING') { @@ -263,6 +295,7 @@ export default function Upload({ {t('modals.uploadDoc.remote')} + {activeTab === 'file' && ( <> )} +
{activeTab === 'file' ? (