[fix]修复服务启动 (#3)

This commit is contained in:
lanceyq
2025-12-04 18:50:09 +08:00
committed by GitHub
parent b9c705998b
commit 0117194a67
23 changed files with 675 additions and 269 deletions

1
.gitignore vendored
View File

@@ -26,7 +26,6 @@ time.log
celerybeat-schedule.db
search_results.json
*.txt
*.json
migrations/versions
tmp
files

View File

@@ -60,6 +60,13 @@ LOG_LEVEL=INFO
# 如需自动迁移数据库:设置 DB_AUTO_UPGRADE=true 或手动执行
alembic upgrade head
# 激活虚拟环境
api\.venv\Scripts\activate
# 目录切换到api下
cd api
# 启动开发服务
uvicorn app.main:app --reload --port 8000

View File

@@ -7,8 +7,8 @@ This module provides utilities for detecting and processing multimodal inputs
import logging
from typing import List
from app.core.memory.agent.multimodal.speech_model import Vico_recognition
# TODO 后续更新
# from app.core.memory.agent.multimodal.speech_model import Vico_recognition
from app.core.memory.agent.utils.llm_tools import picture_model_requests
logger = logging.getLogger(__name__)

View File

@@ -1,8 +1,5 @@
"""
MemSci 记忆系统主入口 - 重构版本
该模块是重构后的记忆系统主入口,使用新的模块化架构。
旧版本入口app/core/memory/src/main.py已删除。
MemSci 记忆系统主入口
主要功能:
1. 协调整个知识提取流水线

View File

@@ -29,7 +29,8 @@ from app.core.memory.agent.utils.mcp_tools import get_mcp_server_config
from app.core.memory.agent.utils.type_classifier import status_typle
from app.db import get_db
from app.repositories.neo4j.neo4j_connector import Neo4jConnector
from app.core.memory.analytics.hot_memory_tags import get_hot_memory_tags
# TODO 后续更新
# from app.core.memory.analytics.hot_memory_tags import get_hot_memory_tags
from app.core.memory.utils.llm.llm_utils import get_llm_client
from app.schemas.memory_storage_schema import ApiResponse, ok, fail
from app.models.knowledge_model import Knowledge, KnowledgeType

View File

@@ -23,10 +23,11 @@ from app.schemas.memory_storage_schema import (
)
from app.repositories.data_config_repository import DataConfigRepository
from app.repositories.neo4j.neo4j_connector import Neo4jConnector
from app.core.memory.analytics.hot_memory_tags import get_hot_memory_tags
from app.core.memory.analytics.memory_insight import MemoryInsight
from app.core.memory.analytics.recent_activity_stats import get_recent_activity_stats
from app.core.memory.analytics.user_summary import generate_user_summary
# TODO 后续更新
# from app.core.memory.analytics.hot_memory_tags import get_hot_memory_tags
# from app.core.memory.analytics.memory_insight import MemoryInsight
# from app.core.memory.analytics.recent_activity_stats import get_recent_activity_stats
# from app.core.memory.analytics.user_summary import generate_user_summary
from app.repositories.data_config_repository import DataConfigRepository
logger = get_logger(__name__)

32
web/.gitignore vendored Normal file
View File

@@ -0,0 +1,32 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.json
# 文档和截图(不上传到仓库)
操作说明.md
记忆熊系统功能使用说明.md
截图清单.md
images/

View File

@@ -1,205 +0,0 @@
# i18n 中英文对比报告
## 📊 统计概览
- **中文键总数**: 1136
- **英文键总数**: 1052
- **中文缺失**: 27 个键
- **英文缺失**: 111 个键
---
## ❌ 英文缺失的翻译111个
### 1. Application 模块 (3个)
- `application.cluster` - 集群
- `application.clusterDesc` - 创建Agent集群
- `application.fullAmount` - 全量
### 2. Role 角色管理模块 (15个)
- `role.roleManagement` - 角色管理
- `role.roleId` - 角色ID
- `role.roleName` - 角色名称
- `role.roleCode` - 角色编码
- `role.description` - 角色描述
- `role.status` - 状态
- `role.enabled` - 已启用
- `role.disabled` - 已停用
- `role.createTime` - 创建时间
- `role.createRole` - 新建角色
- `role.editRole` - 编辑角色
- `role.roleTemplate` - 角色模板
- `role.emptyTemplate` - 空模板
- `role.adminTemplate` - 管理员模板
- `role.userTemplate` - 用户模板
- `role.confirmDelete` - 确定要删除这个角色吗?
- `role.createSuccess` - 角色创建成功
- `role.updateSuccess` - 角色更新成功
- `role.deleteSuccess` - 角色删除成功
- `role.createFailed` - 角色创建失败
- `role.updateFailed` - 角色更新失败
- `role.deleteFailed` - 角色删除失败
### 3. Tenant 租户管理模块 (20个)
- `tenant.tenantId` - 租户ID
- `tenant.tenantName` - 租户名称
- `tenant.contactPerson` - 联系人
- `tenant.contactInfo` - 联系方式
- `tenant.status` - 状态
- `tenant.enabled` - 启用
- `tenant.disabled` - 禁用
- `tenant.expiryDate` - 到期时间
- `tenant.createTenant` - 新增租户
- `tenant.editTenant` - 编辑租户
- `tenant.searchPlaceholder` - 搜索租户ID、名称、联系人或联系方式
- `tenant.confirmDelete` - 确定要删除该租户吗?
- `tenant.confirmBatchDelete` - 确定要批量删除选中的租户吗?
- `tenant.fetchFailed` - 获取租户数据失败
- `tenant.batchEnableSuccess` - 批量启用成功
- `tenant.batchEnableFailed` - 批量启用失败
- `tenant.batchDisableSuccess` - 批量停用成功
- `tenant.batchDisableFailed` - 批量停用失败
- `tenant.exportSuccess` - 导出成功
- `tenant.batchDeleteSuccess` - 批量删除成功
- `tenant.batchDeleteFailed` - 批量删除失败
- `tenant.saveFailed` - 保存失败
- `tenant.batchImport` - 批量导入
### 4. User 用户管理模块 (13个)
- `user.tenantName` - 所属租户
- `user.password` - 密码
- `user.expiryDate` - 有效期
- `user.expiryDateDue` - 有效期至
- `user.batchImport` - 批量导入
- `user.batchImportUser` - 批量导入用户
- `user.downloadTemplate` - 下载导入模板
- `user.templateDownloadSuccess` - 模板下载成功
- `user.startImport` - 开始导入
- `user.batchImportSuccess` - 批量导入成功
- `user.importFailed` - 导入失败,请检查文件格式
- `user.noFileSelected` - 请选择要导入的文件
- `user.onlyXlsxOrCsv` - 只能上传 .xlsx 或 .csv 格式的文件
- `user.reselect` - 重新选择
- `user.noFileSelectedTip` - 未选择任何文件
- `user.downloadTemplateTip` - 请下载模板,填写用户信息后上传。
### 5. Product 产品管理模块 (13个)
- `product.applicationManagement` - 应用管理
- `product.createApplication` - 创建应用
- `product.applicationName` - 应用名称
- `product.applicationIcon` - 应用图标
- `product.applicationNameRequired` - 请输入应用名称
- `product.associationStatus` - 关联状态
- `product.associated` - 已关联
- `product.notAssociated` - 未关联
- `product.unassociate` - 解除关联
- `product.unassociateSuccess` - 解除关联成功
- `product.unassociateFailed` - 解除关联失败
- `product.viewKey` - 查看KEY
- `product.viewStats` - 查看统计
- `product.disableSuccess` - 停用成功
- `product.enableSuccess` - 启用成功
- `product.operationFailed` - 操作失败
### 6. 其他模块 (47个)
- `count` - 计数: {{count}}
- `increment` - 增加
- `decrement` - 减少
- `reset` - 重置
- `switchLanguage` - 切换语言
- `home.title` - 首页
- `home.welcome` - 欢迎使用我们的带单页路由的 React 应用!
- `home.counterCard` - 计数器演示
- `home.aboutCard` - 关于我们
- `home.workflowCard` - 工作流编辑器
- `home.websocketDemoCard` - WebSocket 演示
- `home.sseDemoCard` - SSE演示
- `workflow.title` - 工作流编辑器
- `workflow.description` - 拖拽节点创建连接,构建您的工作流程。点击节点可进行配置。
- `workflow.addNode` - 添加节点
- `workflow.deleteNode` - 删除选中
- `workflow.saveWorkflow` - 保存工作流
- `workflow.startNode` - 触发节点
- `workflow.conditionNode` - 条件判断
- `workflow.actionNode` - 执行动作
- `workflow.endNode` - 结束节点
- `workflow.newNode` - 新节点
- `workflow.node` - 节点
- `workflow.nodesCreated` - 已创建节点
- `workflow.loadingNodes` - 正在加载节点 {{progress}}%
- `workflow.loadingFailed` - 加载节点失败
- `workflow.create5kNodes` - 创建5000节点
- `workflow.create10kNodes` - 创建10000节点
- `notFound.title` - 页面未找到
- `notFound.description` - 请求的页面不存在。
- `notFound.backToHome` - 返回首页
---
## ✅ 中文缺失的翻译27个
### 1. Common 通用模块 (1个)
- `common.operateSuccess` - Operation successful
### 2. KnowledgeBase 知识库模块 (3个)
- `knowledgeBase.models` - Model
- `knowledgeBase.owner` - Owner
- `knowledgeBase.operation` - Operation
### 3. Application 应用模块 (15个)
- `application.multi_agent` - Cluster
- `application.multi_agentDesc` - Create an Agent Cluster
- `application.current` - Current
- `application.versionName` - Version Name
- `application.versionNameTip` - Version number format: v[major version number].[next version number].[revision number] (e.g. v1.3.0)
- `application.agentName` - Agent Name
- `application.roleType` - Role Type
- `application.coordinator` - Coordinator
- `application.analyzer` - Analyzer
- `application.executor` - Executor
- `application.reviewer` - Reviewer
- `application.updateSubAgent` - Update Sub Agent
- `application.subAgentMaxLength` - Sub Agent maximum {{maxLength}}
- `application.capabilities` - Capabilities
### 4. Space 空间模块 (5个)
- `space.storageType` - Storage Type
- `space.rag` - RAG storage
- `space.ragDesc` - Based on vector retrieval, suitable for document Q&A and semantic search
- `space.neo4j` - Graph storage
- `space.neo4jDesc` - Based on knowledge graph, suitable for relational reasoning and path query
### 5. MemoryExtractionEngine 记忆提取引擎模块 (4个)
- `memoryExtractionEngine.coreEntitiesAfterDedup` - Core entities after deduplication
- `memoryExtractionEngine.extractRelationalTriples` - Extracted relational triples (partial)
- `memoryExtractionEngine.extractRelationalTriplesDesc` - There are a total of {{count}} segments with clear semantic boundaries
- `memoryExtractionEngine.theEffectOfEntityDisambiguationLLMDriven` - The effect of entity disambiguation (LLM driven)
---
## 🎯 建议
### 优先级 1 - 核心功能模块(需要立即补充)
1. **Role 角色管理** - 完整模块缺失15个键
2. **Tenant 租户管理** - 完整模块缺失20个键
3. **Product 产品管理** - 完整模块缺失13个键
4. **User 用户管理扩展** - 批量导入功能缺失13个键
### 优先级 2 - 功能增强(建议补充)
1. **Application 应用模块** - 多代理相关功能15个键
2. **Space 空间模块** - 存储类型配置5个键
3. **MemoryExtractionEngine** - 实体去重相关4个键
### 优先级 3 - 演示/测试功能(可选)
1. **Home/Workflow/NotFound** - 演示页面30个键
2. **通用计数器功能** - 测试功能5个键
---
## 📝 下一步行动
1. **补充英文翻译**: 优先补充 Role、Tenant、Product、User 模块的英文翻译
2. **补充中文翻译**: 补充 Application、Space、MemoryExtractionEngine 模块的中文翻译
3. **清理无用翻译**: 如果 Home/Workflow 等演示功能不再使用,可以考虑从中文文件中移除
4. **建立翻译规范**: 建议建立翻译键的命名规范和审查流程,避免未来出现遗漏

72
web/package.json Normal file
View File

@@ -0,0 +1,72 @@
{
"name": "memory-bear-font-end",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"antd": "^5.27.4",
"axios": "^1.12.2",
"clsx": "^2.1.1",
"copy-to-clipboard": "^3.3.3",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.18",
"echarts": "^5.6.0",
"echarts-for-react": "^3.0.2",
"i18next": "^25.6.0",
"mermaid": "^11.12.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.0.0",
"react-infinite-scroll-component": "^6.1.0",
"react-markdown": "^10.1.0",
"react-router-dom": "^6.22.0",
"react-syntax-highlighter": "^16.1.0",
"reactflow": "^11.11.4",
"rehype-katex": "^7.0.1",
"rehype-raw": "^7.0.0",
"remark-breaks": "^4.0.0",
"remark-gfm": "^4.0.1",
"remark-math": "^6.0.0",
"tailwindcss": "^4.1.14",
"zustand": "^5.0.8"
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@tailwindcss/postcss": "^4.1.14",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.14",
"@types/crypto-js": "^4.2.2",
"@types/node": "^24.6.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/react-i18next": "^7.8.3",
"@types/react-router-dom": "^5.3.3",
"@types/react-syntax-highlighter": "^15.5.13",
"@vitejs/plugin-react": "^5.0.4",
"autoprefixer": "^10.4.21",
"eslint": "^9.36.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.22",
"globals": "^16.4.0",
"less": "^4.4.2",
"terser": "^5.44.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.45.0",
"unplugin-auto-import": "^20.2.0",
"unplugin-vue-components": "^29.1.0",
"vite": "npm:rolldown-vite@7.1.14"
},
"overrides": {
"vite": "npm:rolldown-vite@7.1.14"
}
}

View File

@@ -6,22 +6,31 @@
// biome-ignore lint: disable
export {}
declare global {
const Activity: typeof import('react').Activity
const Fragment: typeof import('react').Fragment
const Link: typeof import('react-router-dom').Link
const NavLink: typeof import('react-router-dom').NavLink
const Navigate: typeof import('react-router-dom').Navigate
const Outlet: typeof import('react-router-dom').Outlet
const Route: typeof import('react-router-dom').Route
const Routes: typeof import('react-router-dom').Routes
const Suspense: typeof import('react').Suspense
const cache: typeof import('react').cache
const cacheSignal: typeof import('react').cacheSignal
const createContext: typeof import('react').createContext
const createRef: typeof import('react').createRef
const forwardRef: typeof import('react').forwardRef
const lazy: typeof import('react').lazy
const memo: typeof import('react').memo
const startTransition: typeof import('react').startTransition
const use: typeof import('react').use
const useActionState: typeof import('react').useActionState
const useCallback: typeof import('react').useCallback
const useContext: typeof import('react').useContext
const useDebugValue: typeof import('react').useDebugValue
const useDeferredValue: typeof import('react').useDeferredValue
const useEffect: typeof import('react').useEffect
const useEffectEvent: typeof import('react').useEffectEvent
const useHref: typeof import('react-router-dom').useHref
const useId: typeof import('react').useId
const useImperativeHandle: typeof import('react').useImperativeHandle
@@ -33,6 +42,7 @@ declare global {
const useMemo: typeof import('react').useMemo
const useNavigate: typeof import('react-router-dom').useNavigate
const useNavigationType: typeof import('react-router-dom').useNavigationType
const useOptimistic: typeof import('react').useOptimistic
const useOutlet: typeof import('react-router-dom').useOutlet
const useOutletContext: typeof import('react-router-dom').useOutletContext
const useParams: typeof import('react-router-dom').useParams

View File

@@ -140,7 +140,8 @@ const TableComponent = forwardRef<TableRef, TableComponentProps>(({
const config: { x?: number | string | true; y?: number | string } = {};
if (scrollX !== undefined) {
// 只有在有数据时才应用横向滚动
if (scrollX !== undefined && data.length > 0) {
config.x = scrollX;
} else if (isScroll) {
config.x = 'max-content';

View File

@@ -403,6 +403,7 @@ export const en = {
apiKeyName: 'API Key Name',
},
knowledgeBase: {
selectSpace: 'Please select a workspace.',
preview:'Preview',
pleaseUploadFileFirst: 'Please upload file first',
shareSuccess: 'Share successfully',

View File

@@ -35,6 +35,7 @@ export const zh = {
userMemoryDetail: '用户记忆详情',
},
knowledgeBase: {
selectSpace: '请选择空间',
preview:'预览',
pleaseUploadFileFirst: '请先上传文件',
shareSuccess: '分享成功',

View File

@@ -0,0 +1,46 @@
[
{
"element": "AuthLayout",
"children": [
{ "path": "/user-management", "element": "UserManagement" },
{ "path": "/model", "element": "ModelManagement" },
{ "path": "/space", "element": "SpaceManagement" },
{ "path": "/no-permission", "element": "NoPermission" }
]
},
{
"element": "AuthSpaceLayout",
"children": [
{ "path": "/", "element": "Home" },
{ "path": "/user-memory", "element": "UserMemory" },
{ "path": "/user-memory/:id", "element": "UserMemoryDetail" },
{ "path": "/member", "element": "MemberManagement" },
{ "path": "/memory", "element": "MemoryManagement" },
{ "path": "/forgetting-engine/:id", "element": "ForgettingEngine" },
{ "path": "/memory-extraction-engine/:id", "element": "MemoryExtractionEngine" },
{ "path": "/application", "element": "ApplicationManagement" },
{ "path": "/memory-conversation", "element": "MemoryConversation" },
{ "path": "/knowledge-base", "element": "KnowledgeBase" },
{ "path": "/knowledge-base/:knowledgeBaseId/private", "element": "Private" },
{ "path": "/knowledge-base/:knowledgeBaseId/share", "element": "Share" },
{ "path": "/knowledge-base/:knowledgeBaseId/create-dataset", "element": "CreateDataset" },
{ "path": "/knowledge-base/:knowledgeBaseId/DocumentDetails", "element": "DocumentDetails" },
{ "path": "/no-permission", "element": "NoPermission" },
{ "path": "/*", "element": "NotFound" }
]
},
{
"element": "BasicLayout",
"children": [
{ "path": "/application/config/:id", "element": "ApplicationConfig" },
{ "path": "/conversation/:token", "element": "Conversation" }
]
},
{
"element": "LoginLayout",
"children": [
{ "path": "/login", "element": "Login" },
{ "path": "/invite-register/:token", "element": "InviteRegister" }
]
}
]

248
web/src/store/menu.json Normal file
View File

@@ -0,0 +1,248 @@
{
"manage": [
{
"id": 1,
"parent": 0,
"code": "model",
"label": "模型管理",
"i18nKey": "menu.modelManagement",
"path": "/model",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"subs": []
},
{
"id": 2,
"parent": 0,
"code": "space",
"label": "空间管理",
"i18nKey": "menu.spaceManagement",
"path": "/space",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"subs": []
},
{
"id": 3,
"parent": 0,
"code": "user",
"label": "用户管理",
"i18nKey": "menu.userManagement",
"path": "/user-management",
"enable": true,
"display": true,
"level": 1,
"sort": 2,
"menuDesc": "管理系统用户信息",
"subs": null
}
],
"space": [
{
"id": 4,
"parent": 0,
"code": "dashboard",
"label": "记忆看板",
"i18nKey": "menu.home",
"path": "/",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"subs": null
},
{
"id": 5,
"parent": 0,
"code": "application",
"label": "应用管理",
"i18nKey": "menu.applicationManagement",
"path": "/application",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": null
},
{
"id": 6,
"parent": 0,
"code": "knowledge",
"label": "知识库",
"i18nKey": "menu.knowledgeManagement",
"path": "/knowledge-base",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": [
{
"id": 61,
"parent": 6,
"code": "knowledgePrivate",
"label": "Private",
"i18nKey": "menu.knowledgePrivate",
"path": "/knowledge-base/:knowledgeBaseId/private",
"enable": true,
"display": false,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": null
},
{
"id": 62,
"parent": 6,
"code": "knowledgeShare",
"label": "Share",
"i18nKey": "menu.knowledgeShare",
"path": "/knowledge-base/:knowledgeBaseId/share",
"enable": true,
"display": false,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": null
},
{
"id": 63,
"parent": 6,
"code": "knowledgeCreateDataset",
"label": "CreateDataset",
"i18nKey": "menu.knowledgeCreateDataset",
"path": "/knowledge-base/:knowledgeBaseId/create-dataset",
"enable": true,
"display": false,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": null
},
{
"id": 64,
"parent": 6,
"code": "knowledgeDocumentDetails",
"label": "DocumentDetails",
"i18nKey": "menu.knowledgeDocumentDetails",
"path": "/knowledge-base/:knowledgeBaseId/DocumentDetails",
"enable": true,
"display": false,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": null
}
]
},
{
"id": 7,
"parent": 0,
"code": "memory",
"label": "记忆管理",
"i18nKey": "menu.memoryManagement",
"path": "/memory",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"subs": [
{
"id": 71,
"parent": 7,
"code": "forgettingEngine",
"label": "遗忘引擎",
"i18nKey": "menu.forgettingEngine",
"path": "/forgetting-engine/:id",
"enable": true,
"display": false,
"level": 1,
"sort": 0,
"subs": null
},
{
"id": 72,
"parent": 7,
"code": "memoryExtractionEngine",
"label": "记忆萃取引擎",
"i18nKey": "menu.memoryExtractionEngine",
"path": "/memory-extraction-engine/:id",
"enable": true,
"display": false,
"level": 1,
"sort": 0,
"subs": null
}
]
},
{
"id": 8,
"parent": 0,
"code": "userMemory",
"label": "",
"i18nKey": "menu.userMemory",
"path": "/user-memory",
"enable": true,
"display": true,
"level": 1,
"sort": 1,
"menuDesc": "管理用户记忆",
"subs": [
{
"id": 81,
"parent": 8,
"code": "userMemoryDetail",
"label": "记忆详情",
"i18nKey": "menu.userMemoryDetail",
"path": "/user-memory/:id",
"enable": true,
"display": false,
"level": 2,
"sort": 0,
"subs": null
}
]
},
{
"id": 19,
"parent": 0,
"code": "member",
"label": "成员管理",
"i18nKey": "menu.memberManagement",
"path": "/member",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": null
},
{
"id": 10,
"parent": 0,
"code": "memoryConversation",
"label": "记忆验证",
"i18nKey": "menu.memoryConversation",
"path": "/memory-conversation",
"enable": true,
"display": true,
"level": 1,
"sort": 0,
"icon": null,
"iconActive": null,
"subs": null
}
]
}

View File

@@ -12,17 +12,17 @@ export interface MenuItem {
display: boolean;
level: number;
sort: number;
icon: string | null;
iconActive: string | null;
menuDesc: string | null;
deleted: string | null;
updateTime: number;
new_: string | null;
keepAlive: boolean;
master: string | null;
disposable: boolean;
appSystem: string | null;
subs: MenuItem[];
icon?: string | null;
iconActive?: string | null;
menuDesc?: string | null;
deleted?: string | null;
updateTime?: number;
new_?: string | null;
keepAlive?: boolean;
master?: string | null;
disposable?: boolean;
appSystem?: string | null;
subs: MenuItem[] | null;
}
interface MenuState {
collapsed: boolean;
@@ -31,6 +31,7 @@ interface MenuState {
allBreadcrumbs: Record<'space' | 'manage' | string, MenuItem[]>;
loadMenus: (source: 'space' | 'manage') => void;
updateBreadcrumbs: (keyPath: string[], source: 'space' | 'manage') => void;
setCustomBreadcrumbs: (breadcrumbs: MenuItem[], source: 'space' | 'manage') => void;
}
const initBreadcrumbs = localStorage.getItem('breadcrumbs') || '[]'
@@ -73,4 +74,9 @@ export const useMenu = create<MenuState>((set, get) => ({
set({ allBreadcrumbs })
localStorage.setItem('breadcrumbs', JSON.stringify(allBreadcrumbs))
},
setCustomBreadcrumbs: (breadcrumbs, source) => {
const allBreadcrumbs = { ...get().allBreadcrumbs, [source]: breadcrumbs }
set({ allBreadcrumbs })
localStorage.setItem('breadcrumbs', JSON.stringify(allBreadcrumbs))
},
}))

View File

@@ -145,6 +145,7 @@ const CreateDataset = () => {
});
return;
}
debugger
// 显示确认弹框
confirm({
@@ -195,11 +196,12 @@ const CreateDataset = () => {
title: t('common.deleteWarning'),
content: t('common.deleteWarningContent', { content: record.name }),
onOk: async () => {
// TODO: 实现删除逻辑
const response = await deleteDocument(record.id);
await deleteDocument(record.id);
// 删除成功,刷新列表
// messageApi.success(t('common.deleteSuccess'));
// 删除成功,从 rechunkFileIds 中移除该 id
setRechunkFileIds((prev) => prev.filter((id) => id !== record.id));
// 刷新列表
messageApi.success(t('common.deleteSuccess'));
tableRef.current?.loadData();
@@ -560,6 +562,7 @@ const CreateDataset = () => {
{current === 2 && (
<Spin spinning={pollingLoading} tip={t('knowledgeBase.processingDocuments') || '正在处理文档...'}>
<div className='rb:text-sm rb:text-gray-500 rb:mt-4 rb:h-[calc(100%-160px)] rb:overflow-y-auto'>
{rechunkFileIds.length > 0 ? (
<Table
ref={tableRef}
apiUrl={`/documents/${knowledgeBaseId}/${parentId}/documents`}
@@ -569,6 +572,14 @@ const CreateDataset = () => {
columns={columns}
rowKey="id"
/>
) : (
<Table
ref={tableRef}
columns={columns}
rowKey="id"
initialData={[]}
/>
)}
</div>
</Spin>
)}

View File

@@ -11,10 +11,6 @@ import type { AnyObject } from 'antd/es/_util/type';
import { MoreOutlined } from '@ant-design/icons';
import folderIcon from '@/assets/images/knowledgeBase/folder.png';
import textIcon from '@/assets/images/knowledgeBase/text.png';
import imageIcon from '@/assets/images/knowledgeBase/image.png';
import blankIcon from '@/assets/images/knowledgeBase/blankDocument.png';
import templateIcon from '@/assets/images/knowledgeBase/template.png';
import backupIcon from '@/assets/images/knowledgeBase/backup.png';
import editIcon from '@/assets/images/knowledgeBase/edit.png';
import { getKnowledgeBaseDetail, deleteDocument, downloadFile, updateKnowledgeBase } from '../service';
import type {
@@ -35,6 +31,7 @@ import CreateDatasetModal from '../components/CreateDatasetModal';
import CreateImageDataset from '../components/CreateImageDataset';
import FolderTree, { type TreeNodeData } from '../components/FolderTree';
import { formatDateTime } from '@/utils/format';
import { useMenu } from '@/store/menu';
import './Private.css'
const { confirm } = Modal
// 树节点数据类型
@@ -57,7 +54,6 @@ const Private: FC = () => {
kb_id:knowledgeBaseId ?? '',
parent_id:parentId ?? ''
});
const [keywords, setKeywords] = useState<string>('');
const [query, setQuery] = useState<Record<string, unknown>>({
orderby: 'created_at',
desc: true,
@@ -66,6 +62,8 @@ const Private: FC = () => {
const shareModalRef = useRef<ShareModalRef>(null);
const datasetModalRef = useRef<CreateDatasetModalRef>(null);
const [folderTreeRefreshKey, setFolderTreeRefreshKey] = useState(0);
const { allBreadcrumbs, setCustomBreadcrumbs } = useMenu();
const [folderPath, setFolderPath] = useState<Array<{ id: string; name: string }>>([]);
useEffect(() => {
if (knowledgeBaseId) {
let url = `/documents/${knowledgeBaseId}/${parentId}/documents`;
@@ -74,6 +72,13 @@ const Private: FC = () => {
}
}, [knowledgeBaseId]);
// 更新面包屑
useEffect(() => {
if (knowledgeBase) {
updateBreadcrumbs();
}
}, [knowledgeBase, folderPath]);
// 监听 tableApi 变化,自动刷新表格数据
useEffect(() => {
if (tableApi) {
@@ -95,17 +100,82 @@ const Private: FC = () => {
setLoading(true);
try {
const res = await getKnowledgeBaseDetail(id);
setKnowledgeBase(res.data || res);
// 将 KnowledgeBase 转换为 KnowledgeBaseListItem
const listItem = res as unknown as KnowledgeBaseListItem;
setKnowledgeBase(listItem);
} finally {
setLoading(false);
}
};
// 更新面包屑,包含知识库名称和文件夹路径
const updateBreadcrumbs = () => {
if (!knowledgeBase) return;
const baseBreadcrumbs = allBreadcrumbs['space'] || [];
// 只保留知识库菜单项之前的面包屑
const knowledgeBaseMenuIndex = baseBreadcrumbs.findIndex(item => item.path === '/knowledge-base');
const filteredBaseBreadcrumbs = knowledgeBaseMenuIndex >= 0
? baseBreadcrumbs.slice(0, knowledgeBaseMenuIndex + 1)
: baseBreadcrumbs;
const customBreadcrumbs = [
...filteredBaseBreadcrumbs,
{
id: 0,
parent: 0,
code: null,
label: knowledgeBase.name,
i18nKey: null,
path: null,
enable: true,
display: true,
level: 0,
sort: 0,
icon: null,
iconActive: null,
menuDesc: null,
deleted: null,
updateTime: 0,
new_: null,
keepAlive: false,
master: null,
disposable: false,
appSystem: null,
subs: [],
},
...folderPath.map((folder) => ({
id: 0,
parent: 0,
code: null,
label: folder.name,
i18nKey: null,
path: null,
enable: true,
display: true,
level: 0,
sort: 0,
icon: null,
iconActive: null,
menuDesc: null,
deleted: null,
updateTime: 0,
new_: null,
keepAlive: false,
master: null,
disposable: false,
appSystem: null,
subs: [],
})),
];
setCustomBreadcrumbs(customBreadcrumbs, 'space');
};
// 处理树节点选择
const onSelect = (selectedKeys: React.Key[], info: any) => {
const onSelect = (selectedKeys: React.Key[]) => {
if (!selectedKeys.length) return;
if (!folder) return;
const node = info.node as TreeNodeData;
const f = {
...folder,
parent_id: String(selectedKeys[0]),
@@ -114,17 +184,16 @@ const Private: FC = () => {
setTableApi(url);
setParentId(String(selectedKeys[0]))
setFolder(f)
// 根据节点类型执行不同操作
if (node.type === 'folder') {
};
// 文件夹:展开/收起
} else if (node.type === 'text' || node.type === 'image' || node.type === 'dataset') {
// 文件:打开详情
}
// 处理文件夹路径变化
const handleFolderPathChange = (path: Array<{ id: string; name: string }>) => {
setFolderPath(path);
};
// 处理树节点展开
const onExpand = (expandedKeys: React.Key[], info: any) => {
const onExpand = (_expandedKeys: React.Key[], _info: any) => {
// 展开节点时不需要特殊处理
};
// create / import list
const createItems: MenuProps['items'] = [
@@ -190,10 +259,7 @@ const Private: FC = () => {
// },
];
//
const handleCreate = (type: string) => {
console.log('create', type);
}
// 处理开关
const onChange = (checked: boolean) => {
updateKnowledgeBase(knowledgeBaseId || '', {
@@ -348,8 +414,7 @@ const Private: FC = () => {
title: t('knowledgeBase.status'),
dataIndex: 'progress',
key: 'progress',
render: (value: string | number, record: AnyObject) => {
render: (value: string | number) => {
return (
<span className="rb:text-xs rb:border rb:border-[#DFE4ED] rb:bg-[#FBFDFF] rb:rounded rb:items-center rb:text-[#212332] rb:py-1 rb:px-2">
<span
@@ -445,6 +510,7 @@ const Private: FC = () => {
knowledgeBaseId={knowledgeBaseId ?? ''}
refreshKey={folderTreeRefreshKey}
onRootLoad={handleRootTreeLoad}
onFolderPathChange={handleFolderPathChange}
/>
</div>
)}

View File

@@ -58,6 +58,7 @@ interface FolderTreeProps {
style?: CSSProperties;
refreshKey?: number;
onRootLoad?: (nodes: TreeNodeData[] | null) => void;
onFolderPathChange?: (path: Array<{ id: string; name: string }>) => void;
}
const renderIcon = (icon?: string) => {
@@ -271,6 +272,7 @@ const FolderTree: FC<FolderTreeProps> = ({
style,
refreshKey = 0,
onRootLoad,
onFolderPathChange,
}) => {
const [treeData, setTreeData] = useState<TreeNodeData[]>([]);
@@ -347,6 +349,42 @@ const FolderTree: FC<FolderTreeProps> = ({
}
};
// 查找节点路径的辅助函数
const findNodePath = (nodes: TreeNodeData[], targetKey: Key, currentPath: Array<{ id: string; name: string }> = []): Array<{ id: string; name: string }> | null => {
for (const node of nodes) {
const newPath = [...currentPath, { id: String(node.key), name: String(node.title) }];
if (node.key === targetKey) {
return newPath;
}
if (node.children) {
const found = findNodePath(node.children, targetKey, newPath);
if (found) {
return found;
}
}
}
return null;
};
// 处理选择事件,计算并传递路径
const handleSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
if (selectedKeys.length > 0) {
const path = findNodePath(treeData, selectedKeys[0]);
if (path && onFolderPathChange) {
onFolderPathChange(path);
}
} else if (onFolderPathChange) {
onFolderPathChange([]);
}
// 调用原始的 onSelect 回调
if (onSelect) {
onSelect(selectedKeys, info);
}
};
const treeNodes = useMemo(() => transformTreeData(treeData), [treeData]);
return (
@@ -354,7 +392,7 @@ const FolderTree: FC<FolderTreeProps> = ({
multiple={multiple}
className={className}
style={style}
onSelect={onSelect}
onSelect={handleSelect}
onExpand={onExpand}
loadData={onLoadData}
treeData={treeNodes}

View File

@@ -4,7 +4,7 @@
* @Author: yujiangping
* @Date: 2025-11-10 18:52:55
* @LastEditors: yujiangping
* @LastEditTime: 2025-11-25 17:46:36
* @LastEditTime: 2025-12-03 18:44:58
*/
import { forwardRef, useImperativeHandle, useState } from 'react';
import { Switch } from 'antd';
@@ -24,7 +24,7 @@ const ShareModal = forwardRef<ShareModalRef,ShareModalRefProps>(({ handleShare:
const [messageApi, contextHolder] = message.useMessage();
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false)
const [curIndex, setCurIndex] = useState(9999);
const [curIndex, setCurIndex] = useState(-1);
const [kbId, setKbId] = useState<string>('');
const [spaceIds, setSpaceIds] = useState<string>('');
const [knowledgeBase, setKnowledgeBase] = useState<KnowledgeBase | null>(null);
@@ -32,7 +32,7 @@ const ShareModal = forwardRef<ShareModalRef,ShareModalRefProps>(({ handleShare:
// 封装取消方法,添加关闭弹窗逻辑
const handleClose = () => {
setCurIndex(9999);
setCurIndex(-1);
setLoading(false)
setVisible(false);
};
@@ -53,8 +53,13 @@ const ShareModal = forwardRef<ShareModalRef,ShareModalRefProps>(({ handleShare:
// 获取所有 checked 为 true 的数据
const checkedItems = spaceList.filter(item => item.is_active);
debugger
// 获取当前选中的项curIndex 对应的数据)
const selectedItem = curIndex !== 9999 ? spaceList[curIndex] : null;
const selectedItem = curIndex !== -1 ? spaceList[curIndex] : null;
if(!selectedItem){
messageApi.error(t('knowledgeBase.selectSpace'));
return;
}
const payload = {
source_kb_id: kbId ?? '',
target_workspace_id: selectedItem?.id ?? '',

33
web/tsconfig.app.json Normal file
View File

@@ -0,0 +1,33 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"types": ["vite/client"],
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"],
"exclude": ["**/*copy*"]
}

10
web/tsconfig.json Normal file
View File

@@ -0,0 +1,10 @@
{
"files": [],
"compilerOptions": {
"ignoreDeprecations": "5.0"
},
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

26
web/tsconfig.node.json Normal file
View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}