更新README.md,临时解决文档模式渲染超时问题

This commit is contained in:
zstar 2025-03-25 16:49:38 +08:00
parent 7086f2d11d
commit e9ea71697f
4 changed files with 152 additions and 86 deletions

View File

@ -41,6 +41,17 @@ rm -rf /ragflow/web/dist
docker cp dist ragflow-server:/ragflow/web/ 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 ## TODO
- [ ] 用户批量注册可视化后台管理 - [ ] 用户批量注册可视化后台管理

View File

@ -34,4 +34,4 @@ const App: React.FC = () => {
); );
}; };
export default App; export default App;

View File

@ -12,7 +12,7 @@ export const aiAssistantConfig = {
// 修改为正确的 API 端点格式 // 修改为正确的 API 端点格式
chatEndpoint: "/api/v1/chats", // 创建聊天会话的端点 chatEndpoint: "/api/v1/chats", // 创建聊天会话的端点
completionEndpoint: "/api/v1/chats/{chat_id}/completions", // 聊天完成的端点 completionEndpoint: "/api/v1/chats/{chat_id}/completions", // 聊天完成的端点
timeout: 30000, // 请求超时时间(ms) timeout: 300000, // 请求超时时间(ms)
}, },
// 默认系统提示词 // 默认系统提示词

View File

@ -314,6 +314,25 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
setIsAiLoading(true); setIsAiLoading(true);
// 保存初始光标位置和内容,用于动态更新
const initialCursorPos = cursorPosition;
const initialContent = content;
let beforeCursor = '';
let afterCursor = '';
// 确定插入位置
if (initialCursorPos !== null && showCursorIndicator) {
beforeCursor = initialContent.substring(0, initialCursorPos);
afterCursor = initialContent.substring(initialCursorPos);
}
// 创建一个可以取消的请求控制器
const controller = new AbortController();
// 设置超时定时器
const timeoutId = setTimeout(() => {
controller.abort();
}, aiAssistantConfig.api.timeout || 30000);
try { try {
const authorization = localStorage.getItem('Authorization'); const authorization = localStorage.getItem('Authorization');
if (!authorization) { if (!authorization) {
@ -321,33 +340,42 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
setIsAiLoading(false); setIsAiLoading(false);
return; return;
} }
// 生成一个随机的会话ID // 生成一个随机的会话ID
const conversationId = Math.random().toString(36).substring(2) + Date.now().toString(36); const conversationId = Math.random().toString(36).substring(2) + Date.now().toString(36);
// 创建新会话 // 创建新会话
const createSessionResponse = await axios.post( try {
'v1/conversation/set', const createSessionResponse = await axios.post(
{ 'v1/conversation/set',
dialog_id: dialogId, {
name: "文档撰写对话", dialog_id: dialogId,
is_new: true, name: "文档撰写对话",
conversation_id: conversationId, is_new: true,
message: [ conversation_id: conversationId,
{ message: [
role: "assistant", {
content: "新对话" role: "assistant",
} content: "新对话"
] }
}, ]
{ },
headers: { {
'authorization': authorization headers: {
'authorization': authorization
},
signal: controller.signal
} }
} );
);
if (!createSessionResponse.data?.data?.id) { if (!createSessionResponse.data?.data?.id) {
message.error('创建会话失败'); message.error('创建会话失败');
setIsAiLoading(false);
return;
}
} catch (error) {
console.error('创建会话失败:', error);
message.error('创建会话失败,请重试');
setIsAiLoading(false); setIsAiLoading(false);
return; return;
} }
@ -357,80 +385,99 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
console.log('发送问题到 AI 助手:', aiQuestion); console.log('发送问题到 AI 助手:', aiQuestion);
const response = await axios.post( let lastContent = ''; // 上一次的累积内容
'/v1/conversation/completion',
{
conversation_id: conversationId,
messages: [
{
role: "user",
content: combinedQuestion
}
]
},
{
timeout: aiAssistantConfig.api.timeout,
headers: {
'authorization': authorization
}
}
);
// 修改响应处理逻辑,实现在光标位置插入内容
if (response.data) {
try { try {
const lines = response.data.split('\n').filter((line: string) => line.trim()); const response = await axios.post(
let accumulatedContent = ''; // 累积的内容 '/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) => { if (response.data) {
setTimeout(() => { const lines = response.data.split('\n').filter((line: string) => line.trim());
// 直接处理每一行数据,不使用嵌套的 Promise
for (let i = 0; i < lines.length; i++) {
try { try {
const jsonStr = line.replace('data:', '').trim(); const jsonStr = lines[i].replace('data:', '').trim();
const jsonData = JSON.parse(jsonStr); const jsonData = JSON.parse(jsonStr);
if (jsonData.code === 0 && jsonData.data?.answer) { if (jsonData.code === 0 && jsonData.data?.answer) {
const answer = jsonData.data.answer; const answer = jsonData.data.answer;
// 过滤掉 think 标签内容 // 过滤掉 think 标签内容
const cleanedAnswer = answer.replace(/<think>[\s\S]*?<\/think>/g, '').trim(); const cleanedAnswer = answer.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
// 检查是否还有未闭合的 think 标签 // 检查是否还有未闭合的 think 标签
const hasUnclosedThink = cleanedAnswer.includes('<think>') && const hasUnclosedThink = cleanedAnswer.includes('<think>') &&
(!cleanedAnswer.includes('</think>') || (!cleanedAnswer.includes('</think>') ||
cleanedAnswer.indexOf('<think>') > cleanedAnswer.lastIndexOf('</think>')); cleanedAnswer.indexOf('<think>') > cleanedAnswer.lastIndexOf('</think>'));
if (cleanedAnswer && !hasUnclosedThink) { if (cleanedAnswer && !hasUnclosedThink) {
// 更新累积内容 // 计算新增的内容部分
accumulatedContent = cleanedAnswer; const newContent = cleanedAnswer;
// 在光标位置插入内容 const incrementalContent = newContent.substring(lastContent.length);
if (cursorPosition !== null && showCursorIndicator) {
const beforeCursor = content.substring(0, cursorPosition); // 只有当有新增内容时才更新编辑器
const afterCursor = content.substring(cursorPosition); if (incrementalContent) {
// 更新上一次的内容记录
lastContent = newContent;
// 更新编辑器内容,保持光标位置 // 动态更新编辑器内容
setContent(beforeCursor + accumulatedContent + afterCursor); if (initialCursorPos !== null && showCursorIndicator) {
// 在光标位置动态插入内容
// 更新光标位置到插入内容之后 setContent(beforeCursor + newContent + afterCursor);
const newPosition = cursorPosition + accumulatedContent.length;
setCursorPosition(newPosition); // 更新光标位置到插入内容之后
const newPosition = initialCursorPos + newContent.length;
// 尝试重新设置光标位置 setCursorPosition(newPosition);
setTimeout(() => { } else {
if (textAreaRef.current) { // 如果没有光标位置,则追加到末尾
textAreaRef.current.focus(); setContent(initialContent + newContent);
} }
}, 50);
} else {
// 如果没有光标位置,则追加到末尾
setContent(prev => prev + accumulatedContent);
} }
} }
} }
} catch (parseErr) { } catch (parseErr) {
console.error('解析单行数据失败:', parseErr); console.error('解析单行数据失败:', parseErr);
// 继续处理下一行,不中断整个流程
} }
}, index * 100); // 每100毫秒处理一行
}); // 添加一个小延迟让UI有时间更新
// 在处理完所有响应后,删除临时会话 if (i < lines.length - 1) {
setTimeout(async () => { 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 { try {
await axios.post('/v1/conversation/rm', { await axios.post('/v1/conversation/rm', {
conversation_ids: [conversationId], conversation_ids: [conversationId],
@ -441,21 +488,29 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
} }
}); });
console.log('临时会话已删除:', conversationId); console.log('临时会话已删除:', conversationId);
// 处理完成后,重新设置光标焦点
if (textAreaRef.current) {
textAreaRef.current.focus();
}
} catch (rmErr) { } catch (rmErr) {
console.error('删除临时会话失败:', rmErr); console.error('删除临时会话失败:', rmErr);
// 删除会话失败不影响主流程
} }
}, lines.length * 100 + 500); } catch (err) {
console.error('AI 助手处理失败:', err);
} catch (err) { message.error('AI 助手处理失败,请重试');
console.error('解析响应数据失败:', err); } finally {
message.error('获取 AI 回答失败');
}
}}
finally {
setIsAiLoading(false); setIsAiLoading(false);
// 清空问题输入框
setAiQuestion('');
} }
} }
}; };
// ... existing code ...
return ( return (
<Layout style={{ height: 'auto', padding: 24, overflow: 'hidden'}}> <Layout style={{ height: 'auto', padding: 24, overflow: 'hidden'}}>
<Sider <Sider