feat:替换 Dify 为自建 RAG去实现

1、修复了若干无权限时的失败提示语
2、新增了一个生成后续建议问题的功能
3、重构了知识问答部分的权限管理模块
4、修复了若干渲染不恰当的样式渲染
This commit is contained in:
PingChuan
2026-04-10 16:20:32 +08:00
parent f525707358
commit 5bee9288b9
31 changed files with 407 additions and 304 deletions
+15 -18
View File
@@ -136,36 +136,33 @@ export function useChatApps() {
setLoadingDefault(true);
setError(null);
let resolved = false; // 用局部变量跟踪,避免 React state 异步读取的问题
try {
try {
console.log('[useChatApps] ==================== 开始初始化对话应用 ====================');
// 尝试加载可用应用列表
console.log('[useChatApps] 步骤1: 调用loadChatApps()加载我的应用列表...');
const apps = await loadChatApps();
console.log('[useChatApps] 步骤1完成: 加载到', apps.length, '个应用');
if (apps.length > 0) {
// 查找默认应用
const defaultApp = apps.find((item) => item.is_default) || apps[0];
// console.log('[useChatApps] 默认对话应用:', apps);
setCurrentChatApp(defaultApp);
console.log('[useChatApps] ==================== 初始化完成(路径1 ====================');
resolved = true;
} else {
// 如果没有配置应用,尝试获取默认应用
console.log('[useChatApps] 应用列表为空,调用loadDefaultChatApp()...');
await loadDefaultChatApp();
console.log('[useChatApps] ==================== 初始化完成(路径2 ====================');
const app = await loadDefaultChatApp();
if (app) resolved = true;
}
} catch (err) {
// 加载应用列表失败,尝试获取默认应用
console.warn('[useChatApps] 加载应用列表失败,尝试获取默认应用:', err);
await loadDefaultChatApp();
console.log('[useChatApps] ==================== 初始化完成(路径3 ====================');
const app = await loadDefaultChatApp();
if (app) resolved = true;
}
} catch (err: any) {
console.error('[useChatApps] 初始化失败:', err);
setError(err.message || '加载对话应用失败');
console.warn('[useChatApps] 初始化异常:', err.message);
} finally {
if (!resolved) {
// 权限不足等情况,构造占位应用让页面能渲染(输入框会被禁用)
const fallbackApp = { app_id: '_fallback', app_name: '法务问答', description: '', is_default: true } as any;
setChatApps([fallbackApp]);
setCurrentChatApp(fallbackApp);
setError(null);
}
setLoadingChatApps(false);
setLoadingDefault(false);
setInited(true);
@@ -94,11 +94,24 @@ export function useDocumentDetail(datasetId: string, document: Document | null)
pollIndexingStatus(batch);
}, [stopPolling, pollIndexingStatus]);
// 当文档变化时重置设置
// 当文档变化时,从文档已有的 process_rule 回显设置,无则使用默认值
useEffect(() => {
if (document) {
// 可以从文档中读取已有的设置,这里使用默认值
setSettings(DEFAULT_DOCUMENT_DETAIL_SETTINGS);
const rule = (document as any).process_rule;
if (rule?.mode === 'custom' && rule?.rules) {
const seg = rule.rules.segmentation || {};
const preRules = rule.rules.pre_processing_rules || [];
setSettings({
separator: (seg.separator || '\\n\\n').replace(/\n/g, '\\n'),
maxTokens: seg.max_tokens || DEFAULT_DOCUMENT_DETAIL_SETTINGS.maxTokens,
chunkOverlap: DEFAULT_DOCUMENT_DETAIL_SETTINGS.chunkOverlap,
removeExtraSpaces: preRules.find((r: any) => r.id === 'remove_extra_spaces')?.enabled ?? DEFAULT_DOCUMENT_DETAIL_SETTINGS.removeExtraSpaces,
removeUrlsEmails: preRules.find((r: any) => r.id === 'remove_urls_emails')?.enabled ?? DEFAULT_DOCUMENT_DETAIL_SETTINGS.removeUrlsEmails,
indexingTechnique: DEFAULT_DOCUMENT_DETAIL_SETTINGS.indexingTechnique,
});
} else {
setSettings(DEFAULT_DOCUMENT_DETAIL_SETTINGS);
}
setPreviewSegments([]);
setShowPreview(false);
setIsProcessing(false);
+9 -5
View File
@@ -105,8 +105,10 @@ export function useDatasetManager() {
await loadDocuments(datasetId, 1);
} catch (err: any) {
console.error('[DatasetManager] 加载知识库详情失败:', err);
setError(err.message || '加载知识库失败');
message.error('加载知识库失败');
const is403 = err.message?.includes('403') || err.response?.status === 403;
const msg = is403 ? '您没有查看知识库的权限' : (err.message || '加载知识库失败');
setError(msg);
message.error(msg);
} finally {
setLoadingDataset(false);
}
@@ -151,13 +153,15 @@ export function useDatasetManager() {
setDataset(fullDataset);
await loadDocuments(firstDatasetId, 1);
} else {
setError('未找到知识库,请先在Dify中创建知识库');
setError('未找到知识库,请先联系管理员创建知识库');
}
}
} catch (err: any) {
console.error('[DatasetManager] 加载知识库失败:', err);
setError(err.message || '加载知识库失败');
message.error('加载知识库失败');
const is403 = err.message?.includes('403') || err.response?.status === 403;
const msg = is403 ? '您没有查看知识库的权限' : (err.message || '加载知识库失败');
setError(msg);
message.error(msg);
} finally {
setLoadingDataset(false);
setInited(true);
+1 -1
View File
@@ -72,7 +72,7 @@ export function useAreaDatasetConfig(): UseAreaDatasetConfigReturn {
// 根据权限判断是否可以管理知识库配置
// 权限键:dify:bind:update(知识库绑定更新权限)
// 降级方案:如果 permissionMap 中没有配置权限,usePermission 会自动降级为角色判断
const canManageDataset = hasPermission('dify:bind:update');
const canManageDataset = hasPermission('dify:config:manage');
const canViewDataset = true; // 所有登录用户都可以查看
// 🔍 调试日志(修复后可删除)
+16 -2
View File
@@ -426,11 +426,21 @@ export default function useChatMessage({
resourceCount: messageEnd.metadata?.retriever_resources?.length || 0
});
let needUpdate = false;
// 如果有检索资源,更新响应项
if (messageEnd.metadata?.retriever_resources && messageEnd.metadata.retriever_resources.length > 0) {
responseItem.retriever_resources = messageEnd.metadata.retriever_resources;
needUpdate = true;
}
// 更新聊天列表
// 如果有建议问题,更新响应项
if (messageEnd.metadata?.suggested_questions && messageEnd.metadata.suggested_questions.length > 0) {
responseItem.suggestedQuestions = messageEnd.metadata.suggested_questions;
needUpdate = true;
}
if (needUpdate) {
updateCurrentQA({
responseItem: { ...responseItem },
questionId,
@@ -504,8 +514,12 @@ export default function useChatMessage({
draft[messageIndex].feedback = feedback;
}
}));
} catch (err) {
} catch (err: any) {
logError(`提交反馈时出错: ${err}`);
const msg = err?.message || '提交反馈失败';
const isPermission = msg.includes('403') || msg.includes('权限');
const { message: antMessage } = await import('antd');
antMessage.error(isPermission ? '您没有反馈权限' : msg);
}
}, [logError, getChatList, setChatList]);
+3
View File
@@ -28,6 +28,7 @@ interface RootLoaderData {
permissions?: string[];
permissionMap?: Record<string, string[]>; // ✅ 新增:权限映射表
userRole: string;
userArea?: string;
userInfo?: {
role_id?: number;
role_key?: string;
@@ -70,6 +71,7 @@ export function usePermission() {
// 从root loader获取权限映射表
const permissionMap = rootData?.permissionMap || {};
const userRole = rootData?.userRole || 'common';
const userArea = rootData?.userArea || '';
// 🔑 根据当前路由获取权限列表
const currentPath = location.pathname;
@@ -245,6 +247,7 @@ export function usePermission() {
permissions: currentPermissions, // ✅ 返回当前路由的权限
permissionMap, // ✅ 返回完整的权限映射表
userRole,
userArea,
// 基础检查方法
hasPermission,