更新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

@ -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,10 +340,12 @@ 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);
// 创建新会话 // 创建新会话
try {
const createSessionResponse = await axios.post( const createSessionResponse = await axios.post(
'v1/conversation/set', 'v1/conversation/set',
{ {
@ -342,7 +363,8 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
{ {
headers: { headers: {
'authorization': authorization 'authorization': authorization
} },
signal: controller.signal
} }
); );
@ -351,12 +373,21 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
setIsAiLoading(false); setIsAiLoading(false);
return; return;
} }
} catch (error) {
console.error('创建会话失败:', error);
message.error('创建会话失败,请重试');
setIsAiLoading(false);
return;
}
// 组合当前问题和编辑器内容 // 组合当前问题和编辑器内容
const combinedQuestion = `${aiQuestion}\n\n当前文档内容\n${content}`; const combinedQuestion = `${aiQuestion}\n\n当前文档内容\n${content}`;
console.log('发送问题到 AI 助手:', aiQuestion); console.log('发送问题到 AI 助手:', aiQuestion);
let lastContent = ''; // 上一次的累积内容
try {
const response = await axios.post( const response = await axios.post(
'/v1/conversation/completion', '/v1/conversation/completion',
{ {
@ -372,20 +403,19 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
timeout: aiAssistantConfig.api.timeout, timeout: aiAssistantConfig.api.timeout,
headers: { headers: {
'authorization': authorization 'authorization': authorization
} },
signal: controller.signal
} }
); );
// 修改响应处理逻辑,实现在光标位置插入内容
if (response.data) {
try {
const lines = response.data.split('\n').filter((line: string) => line.trim());
let accumulatedContent = ''; // 累积的内容
// 处理每一行数据 // 修改响应处理逻辑,实现在光标位置动态插入内容
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) {
@ -397,40 +427,57 @@ const handleAiQuestionSubmit = async (e: React.KeyboardEvent<HTMLTextAreaElement
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) {
// 更新累积内容
accumulatedContent = cleanedAnswer;
// 在光标位置插入内容
if (cursorPosition !== null && showCursorIndicator) {
const beforeCursor = content.substring(0, cursorPosition);
const afterCursor = content.substring(cursorPosition);
// 更新编辑器内容,保持光标位置 if (cleanedAnswer && !hasUnclosedThink) {
setContent(beforeCursor + accumulatedContent + afterCursor); // 计算新增的内容部分
const newContent = cleanedAnswer;
const incrementalContent = newContent.substring(lastContent.length);
// 只有当有新增内容时才更新编辑器
if (incrementalContent) {
// 更新上一次的内容记录
lastContent = newContent;
// 动态更新编辑器内容
if (initialCursorPos !== null && showCursorIndicator) {
// 在光标位置动态插入内容
setContent(beforeCursor + newContent + afterCursor);
// 更新光标位置到插入内容之后 // 更新光标位置到插入内容之后
const newPosition = cursorPosition + accumulatedContent.length; const newPosition = initialCursorPos + newContent.length;
setCursorPosition(newPosition); setCursorPosition(newPosition);
// 尝试重新设置光标位置
setTimeout(() => {
if (textAreaRef.current) {
textAreaRef.current.focus();
}
}, 50);
} else { } else {
// 如果没有光标位置,则追加到末尾 // 如果没有光标位置,则追加到末尾
setContent(prev => prev + accumulatedContent); setContent(initialContent + newContent);
}
} }
} }
} }
} catch (parseErr) { } catch (parseErr) {
console.error('解析单行数据失败:', parseErr); console.error('解析单行数据失败:', parseErr);
// 继续处理下一行,不中断整个流程
} }
}, index * 100); // 每100毫秒处理一行
}); // 添加一个小延迟让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);
}
// 在处理完所有响应后,删除临时会话 // 在处理完所有响应后,删除临时会话
setTimeout(async () => {
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) { } catch (err) {
console.error('解析响应数据失败:', err); console.error('AI 助手处理失败:', err);
message.error('获取 AI 回答失败'); message.error('AI 助手处理失败,请重试');
} } finally {
}}
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