From e9ea71697f89f925835b66c4d58c9b5c1d0cf2e4 Mon Sep 17 00:00:00 2001 From: zstar <65890619+zstar1003@users.noreply.github.com> Date: Tue, 25 Mar 2025 16:49:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0README.md=EF=BC=8C=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E8=A7=A3=E5=86=B3=E6=96=87=E6=A1=A3=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E8=B6=85=E6=97=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 + web/src/layouts/index.tsx | 2 +- web/src/pages/write/ai-assistant-config.ts | 2 +- web/src/pages/write/index.tsx | 223 +++++++++++++-------- 4 files changed, 152 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 08573ab..e297f42 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,17 @@ rm -rf /ragflow/web/dist docker cp dist ragflow-server:/ragflow/web/ ``` +## Agent功能恢复 + +由于在我的应用场景中,不需要Agent功能,故隐藏了Agent按钮的入口,如需恢复Agent功能,可修改`web\src\layouts\components\header\index.tsx`,对以下内容取消注释: + +```tsx +{ path: '/flow', name: t('flow'), icon: GraphIcon }, +``` + +同时可将排列样式进行重置,以还原原本的样式布局,修改`web\src\layouts\components\header\index.less`文件,替换为ragflow原始样式:`https://github.com/infiniflow/ragflow/blob/main/web/src/layouts/components/header/index.less` + + ## TODO - [ ] 用户批量注册可视化后台管理 diff --git a/web/src/layouts/index.tsx b/web/src/layouts/index.tsx index a186cb5..c10d7c9 100644 --- a/web/src/layouts/index.tsx +++ b/web/src/layouts/index.tsx @@ -34,4 +34,4 @@ const App: React.FC = () => { ); }; -export default App; +export default App; \ No newline at end of file diff --git a/web/src/pages/write/ai-assistant-config.ts b/web/src/pages/write/ai-assistant-config.ts index c551e80..61d9493 100644 --- a/web/src/pages/write/ai-assistant-config.ts +++ b/web/src/pages/write/ai-assistant-config.ts @@ -12,7 +12,7 @@ export const aiAssistantConfig = { // 修改为正确的 API 端点格式 chatEndpoint: "/api/v1/chats", // 创建聊天会话的端点 completionEndpoint: "/api/v1/chats/{chat_id}/completions", // 聊天完成的端点 - timeout: 30000, // 请求超时时间(ms) + timeout: 300000, // 请求超时时间(ms) }, // 默认系统提示词 diff --git a/web/src/pages/write/index.tsx b/web/src/pages/write/index.tsx index cc2730d..0c364ff 100644 --- a/web/src/pages/write/index.tsx +++ b/web/src/pages/write/index.tsx @@ -314,6 +314,25 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent { + controller.abort(); + }, aiAssistantConfig.api.timeout || 30000); + try { const authorization = localStorage.getItem('Authorization'); if (!authorization) { @@ -321,33 +340,42 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent line.trim()); - let accumulatedContent = ''; // 累积的内容 + const response = await axios.post( + '/v1/conversation/completion', + { + conversation_id: conversationId, + messages: [ + { + role: "user", + content: combinedQuestion + } + ] + }, + { + timeout: aiAssistantConfig.api.timeout, + headers: { + 'authorization': authorization + }, + signal: controller.signal + } + ); - // 处理每一行数据 - lines.forEach((line: string, index: number) => { - setTimeout(() => { + // 修改响应处理逻辑,实现在光标位置动态插入内容 + if (response.data) { + const lines = response.data.split('\n').filter((line: string) => line.trim()); + + // 直接处理每一行数据,不使用嵌套的 Promise + for (let i = 0; i < lines.length; i++) { try { - const jsonStr = line.replace('data:', '').trim(); + const jsonStr = lines[i].replace('data:', '').trim(); const jsonData = JSON.parse(jsonStr); if (jsonData.code === 0 && jsonData.data?.answer) { const answer = jsonData.data.answer; - + // 过滤掉 think 标签内容 const cleanedAnswer = answer.replace(/[\s\S]*?<\/think>/g, '').trim(); // 检查是否还有未闭合的 think 标签 const hasUnclosedThink = cleanedAnswer.includes('') && - (!cleanedAnswer.includes('') || - cleanedAnswer.indexOf('') > cleanedAnswer.lastIndexOf('')); + (!cleanedAnswer.includes('') || + cleanedAnswer.indexOf('') > cleanedAnswer.lastIndexOf('')); + if (cleanedAnswer && !hasUnclosedThink) { - // 更新累积内容 - accumulatedContent = cleanedAnswer; - // 在光标位置插入内容 - if (cursorPosition !== null && showCursorIndicator) { - const beforeCursor = content.substring(0, cursorPosition); - const afterCursor = content.substring(cursorPosition); + // 计算新增的内容部分 + const newContent = cleanedAnswer; + const incrementalContent = newContent.substring(lastContent.length); + + // 只有当有新增内容时才更新编辑器 + if (incrementalContent) { + // 更新上一次的内容记录 + lastContent = newContent; - // 更新编辑器内容,保持光标位置 - setContent(beforeCursor + accumulatedContent + afterCursor); - - // 更新光标位置到插入内容之后 - const newPosition = cursorPosition + accumulatedContent.length; - setCursorPosition(newPosition); - - // 尝试重新设置光标位置 - setTimeout(() => { - if (textAreaRef.current) { - textAreaRef.current.focus(); - } - }, 50); - } else { - // 如果没有光标位置,则追加到末尾 - setContent(prev => prev + accumulatedContent); + // 动态更新编辑器内容 + if (initialCursorPos !== null && showCursorIndicator) { + // 在光标位置动态插入内容 + setContent(beforeCursor + newContent + afterCursor); + + // 更新光标位置到插入内容之后 + const newPosition = initialCursorPos + newContent.length; + setCursorPosition(newPosition); + } else { + // 如果没有光标位置,则追加到末尾 + setContent(initialContent + newContent); + } } } } } catch (parseErr) { console.error('解析单行数据失败:', parseErr); + // 继续处理下一行,不中断整个流程 } - }, index * 100); // 每100毫秒处理一行 - }); - // 在处理完所有响应后,删除临时会话 - setTimeout(async () => { + + // 添加一个小延迟,让UI有时间更新 + if (i < lines.length - 1) { + await new Promise(resolve => setTimeout(resolve, 10)); + } + } + } + } catch (error: any) { + console.error('获取 AI 回答失败:', error); + // 检查是否是超时错误 + if (error.code === 'ECONNABORTED' || error.name === 'AbortError') { + message.error('AI 助手响应超时,请稍后重试'); + } else { + message.error('获取 AI 回答失败,请重试'); + } + } finally { + // 清除超时定时器 + clearTimeout(timeoutId); + } + + // 在处理完所有响应后,删除临时会话 try { await axios.post('/v1/conversation/rm', { conversation_ids: [conversationId], @@ -441,21 +488,29 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent