diff --git a/web/src/api/common.ts b/web/src/api/common.ts new file mode 100644 index 00000000..9a33fd9a --- /dev/null +++ b/web/src/api/common.ts @@ -0,0 +1,33 @@ +import { request } from "@/utils/request"; +// 列表查询参数 +export interface Query { + page?: number; + pagesize?: number; + orderby?: string; + desc?: boolean; + keywords?: string; + [key: string]: unknown; +} +export interface DataResponse { + total_models: Number; + total_llm: Number; + total_embedding: Number; + model_week_growth_rate: Number; + active_workspaces: Number; + new_workspaces_this_week: Number; + workspace_week_growth_rate: Number; + total_users: Number; + new_users_this_week: Number; + user_week_growth_rate: Number; + running_apps: Number; + new_apps_this_week: Number; + app_week_growth_rate: Number +} +// 首页数据统计 +export const getDashboardData = `/home-page/workspaces` + +// 首页数据看板统计 +export const getDashboardStatistics = async () => { + const response = await request.get(`/home-page/statistics`); + return response as DataResponse; +}; \ No newline at end of file diff --git a/web/src/api/knowledgeBase.ts b/web/src/api/knowledgeBase.ts index c8e388a0..a6979b92 100644 --- a/web/src/api/knowledgeBase.ts +++ b/web/src/api/knowledgeBase.ts @@ -285,3 +285,14 @@ export const getRetrievalModeType = async () => { const response = await request.get(`${apiPrefix}/chunks/retrieve_type`); return response as any; }; + +// 获取知识库图谱 +export const getKnowledgeGraph = async (kb_id: string) => { + const response = await request.get(`${apiPrefix}/knowledges/${kb_id}/knowledge_graph`); + return response; +}; +// 获取知识库图谱实体类型 +export const getKnowledgeGraphEntityTypes = async (query: any) => { + const response = await request.get(`${apiPrefix}/knowledges/knowledge_graph_entity_types`,query); + return response ; +}; \ No newline at end of file diff --git a/web/src/api/tools.ts b/web/src/api/tools.ts index 142d4c41..b14905f8 100644 --- a/web/src/api/tools.ts +++ b/web/src/api/tools.ts @@ -27,5 +27,10 @@ export const execute = (data: ExecuteData) => { } export const parseSchema = (data: Record) => { return request.post(`/tools/parse_schema`, data) - +} +export const getToolDetail = (tool_id: string) => { + return request.get(`/tools/${tool_id}`) +} +export const getToolMethods = (tool_id: string) => { + return request.get(`/tools/${tool_id}/methods`) } \ No newline at end of file diff --git a/web/src/assets/images/index/apps.svg b/web/src/assets/images/index/apps.svg new file mode 100644 index 00000000..58907fd6 --- /dev/null +++ b/web/src/assets/images/index/apps.svg @@ -0,0 +1,18 @@ + + + 编组 34 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/arrow_down.svg b/web/src/assets/images/index/arrow_down.svg new file mode 100644 index 00000000..b77a3f8a --- /dev/null +++ b/web/src/assets/images/index/arrow_down.svg @@ -0,0 +1,17 @@ + + + 箭头_向上 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/arrow_down_d.svg b/web/src/assets/images/index/arrow_down_d.svg new file mode 100644 index 00000000..40e5d94b --- /dev/null +++ b/web/src/assets/images/index/arrow_down_d.svg @@ -0,0 +1,18 @@ + + + 编组 30 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/arrow_right.svg b/web/src/assets/images/index/arrow_right.svg new file mode 100644 index 00000000..b2742d11 --- /dev/null +++ b/web/src/assets/images/index/arrow_right.svg @@ -0,0 +1,16 @@ + + + 编组 5 + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/arrow_right_blue.svg b/web/src/assets/images/index/arrow_right_blue.svg new file mode 100644 index 00000000..e83701f1 --- /dev/null +++ b/web/src/assets/images/index/arrow_right_blue.svg @@ -0,0 +1,16 @@ + + + 编组 5 + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/arrow_up.svg b/web/src/assets/images/index/arrow_up.svg new file mode 100644 index 00000000..62aeee96 --- /dev/null +++ b/web/src/assets/images/index/arrow_up.svg @@ -0,0 +1,17 @@ + + + 箭头_向上 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/arrow_up_d.svg b/web/src/assets/images/index/arrow_up_d.svg new file mode 100644 index 00000000..3c19fef3 --- /dev/null +++ b/web/src/assets/images/index/arrow_up_d.svg @@ -0,0 +1,18 @@ + + + 编组 30 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/data_export.svg b/web/src/assets/images/index/data_export.svg new file mode 100644 index 00000000..ba9fee2e --- /dev/null +++ b/web/src/assets/images/index/data_export.svg @@ -0,0 +1,22 @@ + + + 编组 23 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/guide_bg@2x.png b/web/src/assets/images/index/guide_bg@2x.png new file mode 100644 index 00000000..3b7490fb Binary files /dev/null and b/web/src/assets/images/index/guide_bg@2x.png differ diff --git a/web/src/assets/images/index/help_center.svg b/web/src/assets/images/index/help_center.svg new file mode 100644 index 00000000..6d272121 --- /dev/null +++ b/web/src/assets/images/index/help_center.svg @@ -0,0 +1,21 @@ + + + 编组 17 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/index_bg@2x.png b/web/src/assets/images/index/index_bg@2x.png new file mode 100644 index 00000000..d20ee4d3 Binary files /dev/null and b/web/src/assets/images/index/index_bg@2x.png differ diff --git a/web/src/assets/images/index/log_mgt.svg b/web/src/assets/images/index/log_mgt.svg new file mode 100644 index 00000000..66712671 --- /dev/null +++ b/web/src/assets/images/index/log_mgt.svg @@ -0,0 +1,22 @@ + + + 编组 21 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/model_mgt.svg b/web/src/assets/images/index/model_mgt.svg new file mode 100644 index 00000000..89e13ec3 --- /dev/null +++ b/web/src/assets/images/index/model_mgt.svg @@ -0,0 +1,30 @@ + + + 编组 25 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/models.svg b/web/src/assets/images/index/models.svg new file mode 100644 index 00000000..890f240a --- /dev/null +++ b/web/src/assets/images/index/models.svg @@ -0,0 +1,19 @@ + + + 编组 14 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/note_mgt.svg b/web/src/assets/images/index/note_mgt.svg new file mode 100644 index 00000000..5104a37a --- /dev/null +++ b/web/src/assets/images/index/note_mgt.svg @@ -0,0 +1,21 @@ + + + 编组 20 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/space_mgt.svg b/web/src/assets/images/index/space_mgt.svg new file mode 100644 index 00000000..af1db66c --- /dev/null +++ b/web/src/assets/images/index/space_mgt.svg @@ -0,0 +1,20 @@ + + + 编组 26 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/spaces.svg b/web/src/assets/images/index/spaces.svg new file mode 100644 index 00000000..1c61bc6b --- /dev/null +++ b/web/src/assets/images/index/spaces.svg @@ -0,0 +1,26 @@ + + + 编组 32 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/user_mgt.svg b/web/src/assets/images/index/user_mgt.svg new file mode 100644 index 00000000..d53a97b9 --- /dev/null +++ b/web/src/assets/images/index/user_mgt.svg @@ -0,0 +1,22 @@ + + + 编组 24 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/users.svg b/web/src/assets/images/index/users.svg new file mode 100644 index 00000000..545d9636 --- /dev/null +++ b/web/src/assets/images/index/users.svg @@ -0,0 +1,18 @@ + + + 编组 33 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/index/workflow_mgt.svg b/web/src/assets/images/index/workflow_mgt.svg new file mode 100644 index 00000000..8d63dae4 --- /dev/null +++ b/web/src/assets/images/index/workflow_mgt.svg @@ -0,0 +1,21 @@ + + + 编组 29 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/images/workflow/assigner.png b/web/src/assets/images/workflow/assigner.png new file mode 100644 index 00000000..4370bfdd Binary files /dev/null and b/web/src/assets/images/workflow/assigner.png differ diff --git a/web/src/assets/images/workflow/break.png b/web/src/assets/images/workflow/break.png new file mode 100644 index 00000000..473ab068 Binary files /dev/null and b/web/src/assets/images/workflow/break.png differ diff --git a/web/src/assets/images/workflow/question-classifier.png b/web/src/assets/images/workflow/question-classifier.png new file mode 100644 index 00000000..754a0a62 Binary files /dev/null and b/web/src/assets/images/workflow/question-classifier.png differ diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index ee6400f0..0f3f5898 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -3,6 +3,60 @@ export const en = { welcome: 'Welcome to React Font CLI', title: 'Memory Bear.AI ', memoryBear: 'Memory Bear.AI', + index:{ + viewGuide: 'View Guide', + watchVideo: 'Watch Video', + viewDetails: 'View Details', + changeLog: 'Change Log', + latestUpdate: 'Latest Update', + appCount: 'Number of Spaces', + userCount: 'Number of Users', + latestUpdateDesc: 'Version v0.2.0 release: Added visual workflow editor, model performance monitoring panel, and multi tenant permission management system.', + getStarted: 'Getting Started', + startedDesc: 'Understand the core functions of the platform and quickly get started through graphic guidance and video tutorials. Includes a full process demonstration from creating a space to publishing an application.', + spaceTitle:'Memory Bear Intelligent Space Management Platform', + spaceSubTitle: 'Making it easier to implement intelligent models - a one-stop platform for model management, knowledge building, workflow orchestration, and spatial operations', + }, + quickActions:{ + title: 'Quick Actions', + spaceManagement: 'Space Management', + modelManagement: 'Model Management', + workflowOrchestration: 'Workflow Orchestration', + userManagement: 'User Management', + dataExport: 'Data Export', + logQuery:'Log Query', + notificationReminder: 'Notification Reminder', + helpCenter: 'Help Center', + knowledgeBase: 'Knowledge Base', + knowledgeBaseDesc: 'Manage and maintain your knowledge base data', + modelManagementDesc: 'Configure and optimize AI model parameters', + userManagementDesc: 'Manage system users and permission settings', + systemSettings: 'System Settings', + systemSettingsDesc: 'Configure global system parameters and options', + memoryManagement: 'Memory Management', + memoryManagementDesc: 'Manage user memories and conversation history', + apiManagement: 'API Management', + apiManagementDesc: 'Manage API keys and interface configurations', + workflowEngine: 'Workflow Engine', + workflowEngineDesc: 'Design and manage automated workflows', + performanceMonitor: 'Performance Monitor', + performanceMonitorDesc: 'Monitor system performance and operational status', + }, + guide: { + quickStart: 'Quick Start', + createKnowledge: 'Create Knowledge Base', + createKnowledgeDesc: 'Build your exclusive knowledge base to help AI better understand your business', + manageModel: 'Manage Models', + manageModelDesc: 'Configure and manage your AI models to optimize performance', + createSpace: 'Create Space', + createSpaceDesc: 'Create new workspaces to organize your projects and teams', + systemConfig: 'System Configuration', + systemConfigDesc: 'Configure system parameters to personalize your experience', + startCreate: 'Start Creating', + goManage: 'Go Manage', + createNow: 'Create Now', + goConfig: 'Go Configure', + }, menu: { home: 'Home', tenantManagement: 'Tenant Management', @@ -43,12 +97,22 @@ export const en = { orderHistory: 'Order History', }, dashboard: { + total_models: 'Total number of available models', + total_spaces: 'Number of active spaces', + total_users: 'Total number of users', + total_running_apps: 'Number of application runs', + desc_models: 'Contains {{ account }} LLMs and {{ nums }} Embeddings', + desc_spaces: 'more than last week', + desc_users: 'New additions this week', + desc_running_apps: "Today's success rate", totalMemoryCapacity: 'Total Memory Capacity', userMemory: 'User Memory', knowledgeBaseCount: 'Knowledge Base Count', apiCallCount: 'API Call Count', comparedToYesterday: 'compared to yesterday', thisWeek: 'this week', + thisDay: 'day on day', + failureRate: 'Failure Rate', application: 'Application Count', total_num: 'Total Memory Capacity', @@ -630,6 +694,38 @@ export const en = { fileDurationExceeds: 'File duration exceeds the limit', fileDurationLimitError: 'The duration of the media file exceeds the limit. The maximum supported duration is 150 seconds. Current duration', unableReadFile:'Unable to read the information of the media file. Please check the file format.', + // Knowledge Graph related + knowledgeGraph: 'Knowledge Graph', + basicConfig: 'Basic Configuration', + enableKnowledgeGraph: 'Enable Knowledge Graph', + enableKnowledgeGraphTips: 'Once activated, it will automatically construct an entity relationship network.', + graphConfig: 'Graph Configuration', + sceneName: 'Scene Name', + sceneNamePlaceholder: 'Please enter scene name', + entityTypes: 'Entity Types', + entityTypesPlaceholder: 'Please enter entity types, separate multiple types with line breaks', + entityNormalization: 'Entity Normalization', + entityNormalizationTips: 'Merge similar entities when enabled', + entityMethod: 'Entity Method', + entityMethodGeneral: 'General', + entityMethodLight: 'Light', + communityReportGeneration: 'Community Report Generation', + communityReportGenerationTips: 'Generate community analysis reports when enabled', + generateEntityTypes: 'Generate Entity Types', + regenerateEntityTypes: 'Regenerate', + generateEntityTypesSuccess: 'Entity types generated successfully', + generateEntityTypesFailed: 'Failed to generate entity types', + unknownError: 'Unknown error', + pleaseSelectLLMModel: 'Please select a LLM model in basic configuration first', + enterScenarioName: 'Please enter scenario name', + entityDetails: 'Entity Details', + entityDetailEmpty: 'Click on a node in the graph to view details', + entityDetailEmptyDesc: 'Select an entity node to view its detailed information', + entityDescription: 'Entity Description', + graphTitle: 'Knowledge Graph: The Network of Entity, Relationship and Attribute Associations', + graphTips: 'Explore the entity nodes in the knowledge base and their relationship networks', + sourceDocuments: 'Source Documents', + rebuildGraph: 'Rebuild Graph', createForm:{ name: 'Name', embedding_id: 'Embedding', @@ -1117,7 +1213,11 @@ export const en = { memoryContent: 'Memory Content', created_at: 'Created At', - memoryWindow: "{{name}}'s Window of Memory" + memoryWindow: "{{name}}'s Window of Memory", + memory_insight: 'Overall Overview', + key_findings: 'Key Findings', + behavior_pattern: 'Behavior Pattern', + growth_trajectory: 'Growth Trajectory', }, space: { createSpace: 'Create Space', @@ -1580,16 +1680,22 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re 'parameter-extractor': 'Parameter Extraction', flowControl: 'Flow Control', 'if-else': 'Conditional Branch', + 'question-classifier': 'Question Classifier', iteration: 'Iteration', loop: 'Loop', + 'cycle-start': '', + break: 'Break Loop', + assigner: 'Variable Assignment', parallel: 'Parallel Execution', 'var-aggregator': 'Variable Aggregator', externalInteraction: 'External Interaction', "http-request": 'HTTP Request', - tools: 'Tools', + tool: 'Tools', code_execution: 'Code Execution', "jinja-render": 'Template Rendering', cognitiveUpgrading: 'Cognitive Upgrading (Innovation)', + 'memory-read': 'Memory Retrieval', + 'memory-write': 'Memory Storage', task_planning: 'Task Planning', reasoning_control: 'Reasoning Control', self_reflection: 'Self Reflection', @@ -1607,9 +1713,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re clickToConfigure: 'Click to configure node parameters', nodeProperties: 'Node Properties', - empty: "Emmm... The box is empty, nothing here~", + empty: "Emmm…The box is empty, there's nothing here~", nodeName: 'Node Name', - + addvariable: 'Chat Variables', + addChatVariable: 'Add Chat Variable', + editChatVariable: 'Edit Chat Variable', config: { llm: { @@ -1631,7 +1739,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re editVariable: 'Edit Variable', variableType: 'Variable Type', variableName: 'Variable Name', - invalidVariableName: 'Variable name must start with a letter and contain only letters, numbers, and underscores', + invalidVariableName: 'Variable name can only start with English letters and contain English letters, numbers, and underscores', description: 'Display Name', default: 'Default Value', required: 'Required', @@ -1658,10 +1766,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re editParam: 'Edit Extract Parameter', name: 'Name', - invalidParamName: 'Parameter name must start with a letter and contain only letters, numbers, and underscores', + invalidParamName: 'Extract parameter name can only start with English letters and contain English letters, numbers, and underscores', type: 'Type', desc: 'Description', required: 'Required', + default: 'Default Value', 'string': 'String', 'number': 'Number', @@ -1673,7 +1782,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re }, 'var-aggregator': { group: 'Aggregation Group', - invalidVariableName: 'Variable name must start with a letter and contain only letters, numbers, and underscores', + invalidVariableName: 'Variable name can only start with English letters and contain English letters, numbers, and underscores', addGroup: 'Add Group', variable: 'Variable Assignment' }, @@ -1691,7 +1800,76 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re "gt": '>', "ge": '>=', else_desc: 'Used to define the logic that should be executed when the if condition is not met.' - } + }, + 'http-request': { + auth: 'Authentication', + authType: 'Auth Type', + apiKey: 'API Key', + basic: 'Basic', + bearer: 'Bearer', + custom: 'Custom', + header: 'Header', + api_key: 'API Key', + timeouts: 'Timeout Settings', + "connect_timeout": 'Connection Timeout (seconds)', + "read_timeout": 'Read Timeout (seconds)', + "write_timeout": 'Write Timeout (seconds)', + retry: 'Retry on Failure', + error_handle: 'Error Handling', + verify_ssl: 'Verify SSL Certificate', + none: 'None', + default: 'Default Value', + branch: 'Error Branch', + status_code: 'Status Code', + max_attempts: 'Max Retry Attempts', + retry_interval: 'Retry Interval', + }, + 'jinja-render': { + template: 'Code', + mapping: 'Input Variables' + }, + 'question-classifier': { + model_id: 'Model', + input_variable: 'Input Variable', + categories: 'Categories', + user_supplement_prompt: 'Instruction', + class_name: 'Classification', + addClassName: 'Add Classification' + }, + loop: { + cycle_vars: 'Loop Variables', + condition: 'Loop Termination Condition', + }, + assigner: { + assignments: 'Variables', + cover: 'Overwrite', + assign: 'Set', + clear: 'Clear' + }, + iteration: { + input: 'Input Variable', + output: 'Output Variable', + parallel: 'Parallel Mode', + parallel_count: 'Max Parallelism', + flatten: 'Flatten Output', + }, + tool: { + tool_id: 'Tool', + }, + 'memory-read': { + message: 'Message', + config_id: 'Memory Configuration', + search_switch: 'Search Mode', + }, + 'memory-write': { + message: 'Message', + config_id: 'Memory Configuration', + search_switch: 'Search Mode', + }, + name: 'Key', + type: 'Type', + value: 'Value', + addCase: 'Add Condition', }, clear: 'Clear', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index 38fc04d6..4aa03990 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -3,6 +3,60 @@ export const zh = { title: '记忆熊', memoryBear: '记忆熊', welcome: '欢迎使用 React Font CLI', + index:{ + viewGuide: '查看引导', + watchVideo: '观看视频', + viewDetails: '查看详情', + changeLog: '变更日志', + getStarted:'快速开始', + latestUpdate: '最新更新', + appCount: '应用数量', + userCount: '用户数量', + latestUpdateDesc: '版本 v0.2.0 发布:新增了可视化工作流编辑器、模型性能监控面板以及多租户权限管理系统。', + startedDesc: '了解该平台的核心功能,并通过图形指引和视频教程快速上手。包含从创建空间到发布应用程序的整个操作流程演示。', + spaceTitle:'记忆熊智能空间管理平台', + spaceSubTitle: '使智能模型的实施变得更加容易——一个集模型管理、知识构建、工作流程编排以及空间操作于一体的综合性平台', + }, + quickActions:{ + title: '快速操作', + spaceManagement: '空间管理', + modelManagement: '模型管理', + workflowOrchestration: '工作流编排', + userManagement: '用户管理', + dataExport: '数据导出', + logQuery:'日志查询', + notificationReminder: '通知提醒', + helpCenter: '帮助中心', + knowledgeBase: '知识库', + knowledgeBaseDesc: '管理和维护您的知识库数据', + modelManagementDesc: '配置和优化AI模型参数', + userManagementDesc: '管理系统用户和权限设置', + systemSettings: '系统设置', + systemSettingsDesc: '配置系统全局参数和选项', + memoryManagement: '记忆管理', + memoryManagementDesc: '管理用户记忆和对话历史', + apiManagement: 'API管理', + apiManagementDesc: '管理API密钥和接口配置', + workflowEngine: '工作流引擎', + workflowEngineDesc: '设计和管理自动化工作流程', + performanceMonitor: '性能监控', + performanceMonitorDesc: '监控系统性能和运行状态', + }, + guide: { + quickStart: '快速开始', + createKnowledge: '创建知识库', + createKnowledgeDesc: '构建您的专属知识库,让AI更好地理解您的业务', + manageModel: '管理模型', + manageModelDesc: '配置和管理您的AI模型,优化性能表现', + createSpace: '创建空间', + createSpaceDesc: '创建新的工作空间,组织您的项目和团队', + systemConfig: '系统配置', + systemConfigDesc: '配置系统参数,个性化您的使用体验', + startCreate: '开始创建', + goManage: '去管理', + createNow: '立即创建', + goConfig: '去配置', + }, menu: { home: '首页', tenantManagement: '租户管理', @@ -250,6 +304,38 @@ export const zh = { fileDurationExceeds:'文件时长超过限制', fileDurationLimitError: '媒体文件时长超过限制,最大支持150秒,当前时长', unableReadFile:'无法读取媒体文件信息,请检查文件格式', + // 知识图谱相关 + knowledgeGraph: '知识图谱', + basicConfig: '基础配置', + enableKnowledgeGraph: '启用知识图谱', + enableKnowledgeGraphTips: '开启后将自动构建实体关系网络', + graphConfig: '图谱配置', + sceneName: '场景名称', + sceneNamePlaceholder: '请输入场景名称', + entityTypes: '实体类型', + entityTypesPlaceholder: '请输入实体类型,多个类型用换行分隔', + entityNormalization: '实体归一化', + entityNormalizationTips: '开启后将对相似实体进行合并处理', + entityMethod: '实体方法', + entityMethodGeneral: '通用', + entityMethodLight: '轻量', + communityReportGeneration: '社区报告生成', + communityReportGenerationTips: '开启后将生成社区分析报告', + generateEntityTypes: '生成实体类型', + regenerateEntityTypes: '重新生成', + generateEntityTypesSuccess: '实体类型生成成功', + generateEntityTypesFailed: '生成实体类型失败', + unknownError: '未知错误', + pleaseSelectLLMModel: '请先在基础配置中选择大语言模型', + enterScenarioName: '请输入场景名称', + entityDetails: '实体详情', + entityDetailEmpty: '请点击图谱中的节点查看详情', + entityDetailEmptyDesc: '选择一个实体节点来查看其详细信息', + entityDescription: '实体描述', + sourceDocuments: '来源文档', + graphTitle: '知识图谱:实体、关系与属性的关联网络', + graphTips: '探索知识库中的实体节点及其关系脉络', + rebuildGraph: '重建图谱', createForm: { name: '名称', embedding_id: '嵌入模型', @@ -602,12 +688,22 @@ export const zh = { totalRecords: '共 {{total}} 条记录' }, dashboard: { + total_models: '可用模型总数', + total_spaces: '活跃空间数量', + total_users: '用户总数', + total_running_apps: '应用运行次数', + desc_models: '包含 {{ account }} 个大语言模型和 {{ nums }} 个嵌入模型', + desc_spaces: '多于上周', + desc_users: '本周新增', + desc_running_apps: '今日成功率', totalMemoryCapacity: '总记忆容量', userMemory: '用户记忆', knowledgeBaseCount: '知识库数量', apiCallCount: 'API调用次数', comparedToYesterday: '与昨天相比', thisWeek: '本周', + thisDay: '本日', + failureRate: '故障率', application: '应用数量', total_num: '总记忆容量', @@ -1198,7 +1294,11 @@ export const zh = { updated_at: '最后更新时间', fullScreen: '全屏', - memoryWindow: "{{name}}的记忆之窗" + memoryWindow: "{{name}}的记忆之窗", + memory_insight: '总体概述', + key_findings: '关键发现', + behavior_pattern: '行为模式', + growth_trajectory: '成长轨迹', }, space: { createSpace: '创建空间', @@ -1680,16 +1780,22 @@ export const zh = { 'parameter-extractor': '参数提取', flowControl: '流程控制', 'if-else': '条件分支', + 'question-classifier': '问题分类器', iteration: '迭代 (Iteration)', loop: '循环 (Loop)', + 'cycle-start': '', + break: '退出循环', + assigner: '变量赋值', parallel: '并行执行', 'var-aggregator': '变量聚合器', externalInteraction: '外部交互', "http-request": 'HTTP请求', - tools: '工具 (Tools)', + tool: '工具 (Tool)', code_execution: '代码执行', "jinja-render": '模板渲染', cognitiveUpgrading: '认知升级(创新)', + 'memory-read': '记忆提取', + 'memory-write': '记忆储存', task_planning: '任务规划', reasoning_control: '推理控制', self_reflection: '自我反思', @@ -1709,7 +1815,9 @@ export const zh = { nodeProperties: '节点属性', empty: "Emmm…盒子是空的,这里什么都没有~", nodeName: '节点名称', - + addvariable: '会话变量', + addChatVariable: '添加会话变量', + editChatVariable: '编辑会话变量', config: { llm: { @@ -1762,6 +1870,7 @@ export const zh = { type: '类型', desc: '描述', required: '必填', + default: '默认值', 'string': 'String', 'number': 'Number', @@ -1819,9 +1928,48 @@ export const zh = { template: '代码', mapping: '输入变量' }, + 'question-classifier': { + model_id: '模型', + input_variable: '输入变量', + categories: '分类', + user_supplement_prompt: '指令', + class_name: '分类', + addClassName: '添加分类' + }, + loop: { + cycle_vars: '循环变量', + condition: '循环终止条件', + }, + assigner: { + assignments: '变量', + cover: '覆盖', + assign: '设置', + clear: '清空' + }, + iteration: { + input: '输入变量', + output: '输出变量', + parallel: '并行模式', + parallel_count: '最大并行度', + flatten: '扁平化输出', + }, + tool: { + tool_id: '工具', + }, + 'memory-read': { + message: '消息', + config_id: '记忆配置', + search_switch: '检索模式', + }, + 'memory-write': { + message: '消息', + config_id: '记忆配置', + search_switch: '检索模式', + }, name: '键', type: '类型', value: '值', + addCase: '添加条件', }, clear: '清空', diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index 9a2ea17d..bac985bf 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -35,6 +35,7 @@ const componentMap: Record>> = BasicLayout: lazy(() => import('@/components/Layout/BasicLayout')), LoginLayout: lazy(() => import('@/components/Layout/LoginLayout')), // 视图组件 + Index: lazy(() => import('@/views/Index')), Home: lazy(() => import('@/views/Home')), UserMemory: lazy(() => import('@/views/UserMemory')), UserMemoryDetail: lazy(() => import('@/views/UserMemoryDetail')), diff --git a/web/src/routes/routes.json b/web/src/routes/routes.json index 73431f67..a29d1c63 100644 --- a/web/src/routes/routes.json +++ b/web/src/routes/routes.json @@ -2,6 +2,7 @@ { "element": "AuthLayout", "children": [ + { "path": "/index", "element": "Index" }, { "path": "/user-management", "element": "UserManagement" }, { "path": "/model", "element": "ModelManagement" }, { "path": "/space", "element": "SpaceManagement" }, diff --git a/web/src/store/menu.json b/web/src/store/menu.json index 8311e27d..820aaa14 100644 --- a/web/src/store/menu.json +++ b/web/src/store/menu.json @@ -1,5 +1,18 @@ { "manage": [ + { + "id": 999, + "parent": 0, + "code": "dashboard", + "label": "首页", + "i18nKey": "menu.home", + "path": "/index", + "enable": true, + "display": true, + "level": 1, + "sort": 0, + "subs": [] + }, { "id": 1, "parent": 0, diff --git a/web/src/views/ApplicationConfig/components/ConfigHeader.tsx b/web/src/views/ApplicationConfig/components/ConfigHeader.tsx index ec899a32..37a56c80 100644 --- a/web/src/views/ApplicationConfig/components/ConfigHeader.tsx +++ b/web/src/views/ApplicationConfig/components/ConfigHeader.tsx @@ -101,6 +101,9 @@ const ConfigHeader: FC = ({ const clear = () => { workflowRef?.current?.graphRef?.current?.clearCells() } + const addvariable = () => { + workflowRef?.current?.addVariable() + } return ( <>
@@ -132,6 +135,7 @@ const ConfigHeader: FC = ({ {application?.type === 'workflow' ?
+ {/* */} diff --git a/web/src/views/ApplicationConfig/types.ts b/web/src/views/ApplicationConfig/types.ts index abe7a008..3a1c262c 100644 --- a/web/src/views/ApplicationConfig/types.ts +++ b/web/src/views/ApplicationConfig/types.ts @@ -121,7 +121,8 @@ export interface ClusterRef { export interface WorkflowRef { handleSave: (flag?: boolean) => Promise; handleRun: () => void; - graphRef: GraphRef + graphRef: GraphRef; + addVariable: () => void; } export interface ApplicationModalRef { handleOpen: (application?: Config) => void; diff --git a/web/src/views/Index/components/GuideCard.tsx b/web/src/views/Index/components/GuideCard.tsx new file mode 100644 index 00000000..3b61ae72 --- /dev/null +++ b/web/src/views/Index/components/GuideCard.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import guideBgImg from '@/assets/images/index/guide_bg@2x.png' +import { Button } from 'antd'; +import { ArrowRightOutlined } from '@ant-design/icons' +import arrowRight from '@/assets/images/index/arrow_right_blue.svg' +const GuideCard: React.FC = () => { + const { t } = useTranslation(); + + return ( +
+
+ { t('index.getStarted')} +
+
+ { t('index.startedDesc')} +
+
+ + +
+
+ ); +}; + +export default GuideCard; \ No newline at end of file diff --git a/web/src/views/Index/components/QuickActions.tsx b/web/src/views/Index/components/QuickActions.tsx new file mode 100644 index 00000000..7cdb90ec --- /dev/null +++ b/web/src/views/Index/components/QuickActions.tsx @@ -0,0 +1,101 @@ +import { type FC } from 'react'; +import { useTranslation } from 'react-i18next'; + +import modelIcon from '@/assets/images/index/model_mgt.svg' +import spaceIcon from '@/assets/images/index/space_mgt.svg' +import workflowIcon from '@/assets/images/index/workflow_mgt.svg' +import userIcon from '@/assets/images/index/user_mgt.svg' +import dataExportIcon from '@/assets/images/index/data_export.svg' +import logIcon from '@/assets/images/index/log_mgt.svg' +import noteIcon from '@/assets/images/index/note_mgt.svg' +import helpCenterIcon from '@/assets/images/index/help_center.svg' +interface QuickAction { + key: string; + icon: string; + title: string; + onClick?: () => void; +} + +interface QuickActionsProps { + className?: string; + onNavigate?: (path: string) => void; +} + +const QuickActions: FC = ({ onNavigate }) => { + const { t } = useTranslation(); + + const quickActions: QuickAction[] = [ + { + key: 'model-management', + icon: modelIcon, + title: t('quickActions.modelManagement'), + onClick: () => onNavigate?.('/model-management') + }, + { + key: 'space-management', + icon: spaceIcon, + title: t('quickActions.spaceManagement'), + onClick: () => onNavigate?.('/spce') + }, + { + key: 'workflow-orchestration', + icon: workflowIcon, + title: t('quickActions.workflowOrchestration'), + onClick: () => onNavigate?.('/workflow') + }, + { + key: 'user-management', + icon: userIcon, + title: t('quickActions.userManagement'), + onClick: () => onNavigate?.('/user-management') + }, + { + key: 'data-export', + icon: dataExportIcon, + title: t('quickActions.dataExport'), + onClick: () => onNavigate?.('/') + }, + { + key: 'log-query', + icon: logIcon, + title: t('quickActions.logQuery'), + onClick: () => onNavigate?.('/log') + }, + { + key: 'notification-reminder', + icon: noteIcon, + title: t('quickActions.notificationReminder'), + onClick: () => onNavigate?.('/notification-reminder') + }, + + { + key: 'help-center', + icon: helpCenterIcon, + title: t('quickActions.helpCenter'), + onClick: () => onNavigate?.('/help-center') + } + ]; + + return ( +
+
+ { t('quickActions.title') } +
+
+ + {quickActions.map((action) => ( +
+ +
+ {action.title} +
+
+ ))} +
+
); +}; + +export default QuickActions; diff --git a/web/src/views/Index/components/TopCardList/index.module.css b/web/src/views/Index/components/TopCardList/index.module.css new file mode 100644 index 00000000..46ed689c --- /dev/null +++ b/web/src/views/Index/components/TopCardList/index.module.css @@ -0,0 +1,99 @@ +.card { + border-radius: 12px; + border: 1px solid #DFE4ED; + padding: 16px; +} +.header { + line-height: 16px; + font-family: PingFangSC, PingFang SC; + font-weight: 400; + font-size: 12px; + color: #212332; + font-style: normal; + display: flex; + align-items: center; + justify-content: space-between; +} +.headerTitle { + /* Add your header title styles here */ +} +.avatar { + width: 32px; + height: 32px; + background: #FFFFFF; + box-shadow: 0px 2px 6px 0px rgba(33, 35, 50, 0.1); + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + /* margin-right: 12px; */ +} +.avatar img { + width: 32px; + height: 32px; +} +.content { + padding: 24px 24px 8px 0; + display: flex; + justify-content: space-between; + align-items: center; + font-family: Gilroy, Gilroy; + font-weight: 800; + font-size: 28px; + color: #212332; + text-align: left; + font-style: normal; +} +.content-right { + text-align: right; + font-family: PingFangSC, PingFang SC; + font-weight: 400; + font-size: 12px; + color: #5F6266; + line-height: 16px; + font-style: normal; + row-gap: 4px; +} +.trend { + font-family: PingFangSC, PingFang SC; + font-weight: 500; + font-size: 14px; + line-height: 16px; + font-style: normal; + padding-left: 15px; + position: relative; + margin-bottom: 4px; + display: inline-block; +} +.trend::before { + width: 14px; + height: 14px; + content: ''; + position: absolute; + left: 0; + top: 1px; + background-repeat: no-repeat; + background-size: contain; +} +.trend.up { + color: #369F21; +} +.trend.up::before { + background-image: url('@/assets/images/home/arrow_up_success.svg'); +} +.trend.down { + color: #FF5D34; +} +.trend.down::before { + background-image: url('@/assets/images/home/arrow_down.png'); +} + +.trend-desc { + font-family: PingFangSC, PingFang SC; + font-weight: 500; + font-size: 14px; + color: #155EEF; + line-height: 16px; + text-align: left; + font-style: normal; +} \ No newline at end of file diff --git a/web/src/views/Index/components/TopCardList/index.tsx b/web/src/views/Index/components/TopCardList/index.tsx new file mode 100644 index 00000000..273ce936 --- /dev/null +++ b/web/src/views/Index/components/TopCardList/index.tsx @@ -0,0 +1,133 @@ +import { type FC } from 'react' +import { useTranslation } from 'react-i18next' +import totalModels from '@/assets/images/index/models.svg'; +import totalSpaces from '@/assets/images/index/spaces.svg'; +import totalUsers from '@/assets/images/index/users.svg'; +import totalApps from '@/assets/images/index/apps.svg'; +import arrowUpDb from '@/assets/images/index/arrow_up_d.svg' +import arrowDownDb from '@/assets/images/index/arrow_down_d.svg' +import arrowUp from '@/assets/images/index/arrow_up.svg' +import arrowDown from '@/assets/images/index/arrow_down.svg' +import styles from './index.module.css' +import { type DataResponse } from '@/api/common' + +const list = [ + { + key: 'models', + icon: totalModels, + value: '24', + // trendValue: '12.5%', + trend: 'up', + // trendDesc: 'comparedToYesterday', + rate:"up", + rateValue: '12%', + background: 'linear-gradient( 136deg, rgba(21,94,239,0.06) 0%, rgba(251,253,255,0) 100%)' + }, + { + key: 'spaces', + icon: totalSpaces, + value: '156', + trendValue: '+8', + trend: 'down', + rate:"up", + rateValue: '5.4%', + // trendDesc: 'comparedToYesterday', + background: 'linear-gradient( 134deg, rgba(54,159,33,0.06) 0%, rgba(251,253,255,0) 100%)', + }, + { + key: 'users', + icon: totalUsers, + value: '1,248', + trendValue: '+42', + trend: 'up', + rate:"up", + rateValue: '12%', + // trendDesc: 'thisWeek', + background: 'linear-gradient( 136deg, rgba(77,168,255,0.06) 0%, rgba(251,253,255,0) 100%)', + }, + { + key: 'running_apps', + icon: totalApps, + value: '12.8k', + trendValue: '98.7%', + trend: 'up', + rate:"down", + rateValue: '2.1%', + // trendDesc: 'comparedToYesterday', + background: 'linear-gradient( 136deg, rgba(156,111,255,0.06) 0%, rgba(251,253,255,0) 100%)', + }, +] +const TopCardList: FC<{data?: DataResponse}> = ({ data }) => { + const { t } = useTranslation() + return ( +
+ {list.map((item) => { + return ( +
+
+
{t(`dashboard.${'total_' + item.key}`)}
+
+
+ +
+ {item.key === 'spaces' && String(data?.active_workspaces)} + {item.key !== 'spaces' && String(data?.[`total_${item.key}` as keyof DataResponse] || item.value || 0)} +
+
+ {item.key === 'models' ? ( +
+ {t(`dashboard.${'desc_' + item.key}`, { account: data?.total_llm, nums: data?.total_embedding })} +
+ ) : (<> +
+ {item.key === 'spaces' && (<> + = 0 ? arrowUpDb : arrowDownDb} className='rb:size-3'/> + = 0 ? 'rb:text-[#369F21]' : 'rb:text-[#FF5D34]'}>{Number(data?.new_workspaces_this_week || 0) >= 0 ? '+' : '-'}{Math.abs(Number(data?.new_workspaces_this_week || 0))} + )} + {item.key === 'users' && (<> + = 0 ? arrowUpDb : arrowDownDb} className='rb:size-3'/> + = 0 ? 'rb:text-[#369F21]' : 'rb:text-[#FF5D34]'}>{Number(data?.new_users_this_week || 0) >= 0 ? '+' : '-'}{Math.abs(Number(data?.new_users_this_week || 0))} + )} + {item.key === 'running_apps' && (<> + = 0 ? arrowUpDb : arrowDownDb} className='rb:size-3'/> + = 0 ? 'rb:text-[#369F21]' : 'rb:text-[#FF5D34]'}>{Number(data?.new_apps_this_week || 0) >= 0 ? '+' : '-'}{Math.abs(Number(data?.new_apps_this_week || 0))} + )} + +
+
+ {t(`dashboard.${'desc_' + item.key}`)} +
+ )} +
+ + {item.key === 'models' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.model_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + {item.key === 'spaces' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.workspace_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + {item.key === 'users' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.user_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + {item.key === 'running_apps' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.app_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + +
+ ) + })} +
+ ) +} + +export default TopCardList \ No newline at end of file diff --git a/web/src/views/Index/components/VersionCard.tsx b/web/src/views/Index/components/VersionCard.tsx new file mode 100644 index 00000000..3967dac4 --- /dev/null +++ b/web/src/views/Index/components/VersionCard.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button } from 'antd'; +import arrowRight from '@/assets/images/index/arrow_right.svg' +const GuideCard: React.FC = () => { + const { t } = useTranslation(); + + return ( +
+
+ { t('index.latestUpdate')} +
+
+ { t('index.latestUpdateDesc')} +
+
+ + +
+
+ ); +}; + +export default GuideCard; \ No newline at end of file diff --git a/web/src/views/Index/index.tsx b/web/src/views/Index/index.tsx new file mode 100644 index 00000000..e6265d3b --- /dev/null +++ b/web/src/views/Index/index.tsx @@ -0,0 +1,143 @@ +import { useEffect, useState, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { Row, Col, Space, Button } from 'antd'; +import TopCardList from './components/TopCardList'; +import GuideCard from './components/GuideCard'; +import VersionCard from './components/VersionCard'; +import QuickActions from './components/QuickActions'; +import bgImg from '@/assets/images/index/index_bg@2x.png' +import Table, { type TableRef } from '@/components/Table' +import type { ColumnsType } from 'antd/es/table'; +import { formatDateTime } from '@/utils/format'; +import { + getDashboardData, + getDashboardStatistics, + type DataResponse } from '@/api/common'; +import { switchWorkspace } from '@/api/workspaces' +const Index = () => { + const { t } = useTranslation(); + const navigate = useNavigate() + const [dashboardData, setDashboardData] = useState(); + const tableRef = useRef(null); + const tableApi = getDashboardData; + const getDashboardCount = async () => { + try{ + const res = await getDashboardStatistics(); + setDashboardData(res); + }catch(e) { + console.log(e) + } + } + const handleJump = (id: string) => { + switchWorkspace(id) + .then(() => { + localStorage.removeItem('user') + navigate('/') + }) + } + const columns: ColumnsType = [ + { + title: t('space.spaceName'), + dataIndex: 'name', + key: 'name', + }, + + { + title: t('space.spaceIcon'), + dataIndex: 'icon', + key: 'icon', + render:(value: string, record: any) => { + return value ? ( + icon + ) : ( +
+ {record.name?.charAt(0)?.toUpperCase() || '?'} +
+ ) + } + }, + { + title: t('index.appCount'), + dataIndex: 'app_count', + key: 'app_count', + }, + { + title: t('index.userCount'), + dataIndex: 'user_count', + key: 'user_count', + }, + { + title: t('apiKey.createdAt'), + dataIndex: 'created_at', + key: 'created_at', + render:(value:string) => { + return( + {formatDateTime(Number(value) ,'YYYY-MM-DD HH:mm:ss')} + ) + } + }, + { + title: t('common.operation'), + key: 'action', + fixed: 'right', + width: 100, + render: (_, record) => ( + + + + ), + }, + ] + + useEffect(() => { + tableRef.current?.loadData(); + }, [tableApi]); + useEffect(() => { + getDashboardCount(); + }, []) + + + return ( +
+ + +
+
+ { t('index.spaceTitle' )} +
+
+ { t('index.spaceSubTitle' )} +
+
+ {/* 统计卡片 */} + +
+ + + + + {/* 引导 */} + +
+ +
+ {/* 快捷操作 */} +
+ +
+ + + + + + ); +} + +export default Index \ No newline at end of file diff --git a/web/src/views/Index/types.ts b/web/src/views/Index/types.ts new file mode 100644 index 00000000..437c54e3 --- /dev/null +++ b/web/src/views/Index/types.ts @@ -0,0 +1,13 @@ +export interface TopCardListProps { + title:string; + description:string; + icon: Element; + number: number; + label: string; +} +export interface DashboardData { + total_models:number; + total_spaces:number; + total_users:number; + total_apps_runs: string; +} \ No newline at end of file diff --git a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx index 136dc615..d6d5ee4f 100644 --- a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx +++ b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx @@ -2,18 +2,18 @@ import { useEffect, useState, useRef, useCallback, type FC } from 'react'; import { useNavigate, useParams, useLocation } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { Switch, Button, Dropdown, Space, Modal, message } from 'antd'; +import { Switch, Button, Dropdown, Space, Modal, message, Radio } from 'antd'; import type { MenuProps } from 'antd'; import SearchInput from '@/components/SearchInput' import Table, { type TableRef } from '@/components/Table' import type { ColumnsType } from 'antd/es/table'; import type { AnyObject } from 'antd/es/_util/type'; -import { MoreOutlined } from '@ant-design/icons'; +import { MoreOutlined, DeploymentUnitOutlined, BarsOutlined } from '@ant-design/icons'; import folderIcon from '@/assets/images/knowledgeBase/folder.png'; import textIcon from '@/assets/images/knowledgeBase/text.png'; import editIcon from '@/assets/images/knowledgeBase/edit.png'; -import blankIcon from '@/assets/images/knowledgeBase/blankDocument.png'; -import imageIcon from '@/assets/images/knowledgeBase/image.png' +// import blankIcon from '@/assets/images/knowledgeBase/blankDocument.png'; +// import imageIcon from '@/assets/images/knowledgeBase/image.png' import { getKnowledgeBaseDetail, deleteDocument, downloadFile, updateKnowledgeBase } from '@/api/knowledgeBase'; import { type CreateModalRef, @@ -22,8 +22,10 @@ import { type CreateFolderModalRef, type CreateSetModalRef, type ShareModalRef, - type CreateDatasetModalRef,type FolderFormData, - type KnowledgeBaseDocumentData, + type CreateDatasetModalRef, + type FolderFormData, + type KnowledgeBaseDocumentData, + type KnowledgeBaseFormData, } from '@/views/KnowledgeBase/types'; import RecallTestDrawer from '../components/RecallTestDrawer'; import CreateFolderModal from '../components/CreateFolderModal'; @@ -34,7 +36,7 @@ import CreateDatasetModal from '../components/CreateDatasetModal'; import CreateImageDataset from '../components/CreateImageDataset'; import FolderTree, { type TreeNodeData } from '../components/FolderTree'; import { formatDateTime } from '@/utils/format'; - +import KnowledgeGraphCard from '../components/KnowledgeGraphCard'; import { useBreadcrumbManager, type BreadcrumbItem } from '@/hooks/useBreadcrumbManager'; import './Private.css' const { confirm } = Modal @@ -68,7 +70,7 @@ const Private: FC = () => { const datasetModalRef = useRef(null); const [folderTreeRefreshKey, setFolderTreeRefreshKey] = useState(0); const [autoExpandPath, setAutoExpandPath] = useState>([]); - + const [isGraph, setIsGraph] = useState(false); const { updateBreadcrumbs } = useBreadcrumbManager({ breadcrumbType: 'detail', // 不提供 onKnowledgeBaseMenuClick,让它使用默认的导航行为(返回列表页面) @@ -376,9 +378,37 @@ const Private: FC = () => { // 处理开关 const onChange = (checked: boolean) => { - updateKnowledgeBase(knowledgeBaseId || '', { + if (!knowledgeBase) return; + + // 构造完整的更新数据,保留现有配置 + const updateData: KnowledgeBaseFormData = { + name: knowledgeBase.name, + description: knowledgeBase.description, + embedding_id: knowledgeBase.embedding_id, + llm_id: knowledgeBase.llm_id, + image2text_id: knowledgeBase.image2text_id, + reranker_id: knowledgeBase.reranker_id, + permission_id: knowledgeBase.permission_id, + type: knowledgeBase.type, status: checked ? 1 : 0, - }); + parser_config: knowledgeBase.parser_config || { + chunk_token_num: 512, + delimiter: '\n', + auto_keywords: 0, + auto_questions: 0, + html4excel: false, + graphrag: { + use_graphrag: false, + scene_name: '', + entity_types: [], + method: '', + resolution: false, + community: false + } + } + }; + + updateKnowledgeBase(knowledgeBaseId || '', updateData); console.log(`switch to ${checked}`); }; // 处理搜索 @@ -626,17 +656,15 @@ const Private: FC = () => { } const handleRefreshTable = () => { - debugger // 刷新表格数据 tableRef.current?.loadData(); } - return ( <> {contextHolder}
{folder && ( -
+
{
+ setIsGraph(e.target.value)}> + + + + + + + @@ -688,14 +724,21 @@ const Private: FC = () => {
-
} - columns={columns} - rowKey="id" - scrollX={1500} - /> + {isGraph ? ( + modalRef.current?.handleOpen(knowledgeBase, 'rebuild')} + /> + ) : ( +
} + columns={columns} + rowKey="id" + scrollX={1500} + /> + )} (({ refreshTable }, ref) => { const { t } = useTranslation(); + const [messageApi, contextHolder] = message.useMessage(); const [visible, setVisible] = useState(false); const [modelTypeList, setModelTypeList] = useState([]); const [modelOptionsByType, setModelOptionsByType] = useState>({}); const [datasets, setDatasets] = useState(null); const [currentType, setCurrentType] = useState<'General' | 'Web' | 'Third-party' | 'Folder'>('General'); const [form] = Form.useForm(); - const [loading, setLoading] = useState(false) + const [loading, setLoading] = useState(false); + const [activeTab, setActiveTab] = useState('basic'); + const [generatingEntityTypes, setGeneratingEntityTypes] = useState(false); + const [isRebuildMode, setIsRebuildMode] = useState(false); + + // 监听 parser_config.graphrag 相关字段的变化 + const parserConfig = Form.useWatch('parser_config', form); + const graphragConfig = parserConfig?.graphrag; + const enableKnowledgeGraph = graphragConfig?.use_graphrag || false; + const entityTypes = graphragConfig?.entity_types || ''; + const entityNormalization = graphragConfig?.resolution || false; + const communityReportGeneration = graphragConfig?.community || false; // 封装取消方法,添加关闭弹窗逻辑 const handleClose = () => { setDatasets(null); form.resetFields(); - setLoading(false) + setLoading(false); + setActiveTab('basic'); + setIsRebuildMode(false); // 重置重建模式标识 setVisible(false); }; + // 生成实体类型的函数 + const generateEntityTypes = async () => { + const sceneName = form.getFieldValue(['parser_config', 'graphrag', 'scene_name']); + if (!sceneName) { + // 可以添加提示用户输入场景名称 + messageApi.error(t('knowledgeBase.enterScenarioName')); + return; + } + + // 检查是否选择了 LLM 模型 + const llmId = form.getFieldValue('llm_id'); + if (!llmId) { + // 跳转到基础配置页 + setActiveTab('basic'); + messageApi.error(t('knowledgeBase.pleaseSelectLLMModel')); + return; + } + + setGeneratingEntityTypes(true); + try { + // 这里应该调用实际的API接口 + // const user = JSON.parse(localStorage.getItem('user') as any); + //datasets?.id || datasets?.parent_id || user?.current_workspace_id, + const params = { + scenario: sceneName, + llm_id: llmId + }; + const response = await getKnowledgeGraphEntityTypes(params); + // 模拟API调用 + // await new Promise(resolve => setTimeout(resolve, 1000)); + + // 处理API响应数据 + console.log('API Response:', response); // 调试日志 + + // 检查响应结构 - API直接返回字符串 + if (response && typeof response === 'string' && response.trim()) { + // 将逗号分隔的字符串转换为换行分隔的格式以便在TextArea中显示 + const entityTypesString = response.replace(/,\s*/g, '\n'); + console.log('Converted entity types:', entityTypesString); // 调试日志 + + const currentGraphrag = form.getFieldValue(['parser_config', 'graphrag']) || {}; + const updatedGraphrag = { + ...currentGraphrag, + entity_types: entityTypesString + }; + + console.log('Updating form with:', updatedGraphrag); // 调试日志 + + // 使用更直接的方式更新表单字段 + form.setFieldValue(['parser_config', 'graphrag', 'entity_types'], entityTypesString); + + // 强制触发表单重新渲染 + form.validateFields([['parser_config', 'graphrag', 'entity_types']]); + + // 额外的强制更新机制 + setTimeout(() => { + form.setFieldValue(['parser_config', 'graphrag', 'entity_types'], entityTypesString); + }, 100); + + messageApi.success(t('knowledgeBase.generateEntityTypesSuccess')); + } else { + messageApi.error(t('knowledgeBase.generateEntityTypesFailed') + ':' + t('knowledgeBase.unknownError')); + } + } catch (error) { + console.error(t('knowledgeBase.generateEntityTypesFailed') + ':', error); + } finally { + setGeneratingEntityTypes(false); + } + }; + const typeToFieldKey = (type: string): string => { switch ((type || '').toLowerCase()) { case 'embedding': @@ -89,6 +179,30 @@ const CreateModal = forwardRef(({ type: type || record.type || currentType, status: record.status, }; + + // 处理 parser_config 配置数据,如果没有则设置默认值 + baseValues.parser_config = record.parser_config || { + graphrag: { + use_graphrag: false, + scene_name: '', + entity_types: [] as any, + method: 'general', + resolution: false, + community: false, + } + }; + + // 如果存在 entity_types,转换为换行分隔格式用于 TextArea 显示 + if (baseValues.parser_config.graphrag.entity_types) { + if (Array.isArray(baseValues.parser_config.graphrag.entity_types)) { + // 如果是数组格式,转换为换行分隔字符串 + (baseValues.parser_config.graphrag as any).entity_types = baseValues.parser_config.graphrag.entity_types.join('\n'); + } else if (typeof baseValues.parser_config.graphrag.entity_types === 'string') { + // 如果是逗号分隔字符串格式,转换为换行分隔字符串(兼容旧数据) + (baseValues.parser_config.graphrag as any).entity_types = (baseValues.parser_config.graphrag.entity_types as string).replace(/,\s*/g, '\n'); + } + } + form.setFieldsValue(baseValues); }; @@ -112,6 +226,15 @@ const CreateModal = forwardRef(({ setDatasets(record || null); const nextType = type || currentType; setCurrentType(nextType as any); + setIsRebuildMode(type === 'rebuild'); // 设置重建模式标识 + + // 如果是重建模式,默认切换到知识图谱标签页 + if (type === 'rebuild') { + setActiveTab('knowledgeGraph'); + } else { + setActiveTab('basic'); + } + setBaseFields(record || null, nextType); getTypeList(record || null); setVisible(true); @@ -142,12 +265,26 @@ const CreateModal = forwardRef(({ .then(() => { setLoading(true) const formValues = form.getFieldsValue(); + + // 处理 entity_types 格式转换:从换行分隔字符串转换为字符串数组 + if (formValues.parser_config && formValues.parser_config.graphrag && formValues.parser_config.graphrag.entity_types) { + const entityTypesString = formValues.parser_config.graphrag.entity_types as any as string; + const entityTypesArray = entityTypesString + .split('\n') + .map((item: string) => item.trim()) + .filter((item: string) => item.length > 0); + formValues.parser_config.graphrag.entity_types = entityTypesArray; + } + const payload: KnowledgeBaseFormData = { ...formValues, type: formValues.type || currentType, permission_id: formValues.permission_id || 'Private', parent_id: datasets?.parent_id || undefined, }; + + console.log('Saving payload:', payload); // 调试日志 + const submit = datasets?.id ? updateKnowledgeBase(datasets.id, payload) : createKnowledgeBase(payload); @@ -194,6 +331,9 @@ const CreateModal = forwardRef(({ // 根据 type 获取标题 const getTitle = () => { + if (isRebuildMode) { + return t('knowledgeBase.rebuildGraph') + ' - ' + (datasets?.name || ''); + } if (datasets?.id) { return t('knowledgeBase.edit') + ' ' + datasets.name; } @@ -205,6 +345,192 @@ const CreateModal = forwardRef(({ const dynamicTypeList = useMemo(() => modelTypeList.filter((tp) => (modelOptionsByType[tp] || []).length), [modelTypeList, modelOptionsByType]); + // 基础配置表单内容 + const renderBasicConfig = () => ( + <> + {!datasets?.id && ( + + + + )} + +