From 0aa8fa10c1f05939e8304f5eaad6cb68b09369a5 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Fri, 25 Apr 2025 10:14:31 +0800 Subject: [PATCH 01/74] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9=E4=BA=8E=20th?= =?UTF-8?q?ink=20=E6=A0=87=E7=AD=BE=E7=9A=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/ChatComponent.vue | 37 ++++++++++++++++++++++++- web/src/components/MessageComponent.vue | 4 +-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/web/src/components/ChatComponent.vue b/web/src/components/ChatComponent.vue index a4fe2578e..23ea2d5ac 100644 --- a/web/src/components/ChatComponent.vue +++ b/web/src/components/ChatComponent.vue @@ -347,7 +347,42 @@ const updateMessage = (info) => { try { // 特殊处理:content需要追加而不是替换 if (info.content != null && info.content !== '') { - msg.content += info.content; + // 检查新内容中是否有标签 + if (info.content.includes('') && !msg.isCollectingThinking) { + // 开始收集思考内容 + msg.isCollectingThinking = true; + + // 分割内容,获取标签前后的部分 + const parts = info.content.split(''); + msg.content += parts[0]; // 添加标签前的内容到正文 + + // 如果有标签后的内容,添加到思考内容 + if (parts.length > 1) { + if (parts[1].includes('')) { + const thinkParts = parts[1].split(''); + msg.reasoning_content = (msg.reasoning_content || '') + thinkParts[0]; + msg.content += thinkParts[1]; // 添加结束标签后的内容到正文 + msg.isCollectingThinking = false; + } else { + msg.reasoning_content = (msg.reasoning_content || '') + parts[1]; + } + } + } + // 检查是否正在收集思考内容 + else if (msg.isCollectingThinking) { + if (info.content.includes('')) { + const parts = info.content.split(''); + msg.reasoning_content = (msg.reasoning_content || '') + parts[0]; + msg.content += parts[1]; // 添加结束标签后的内容到正文 + msg.isCollectingThinking = false; + } else { + msg.reasoning_content = (msg.reasoning_content || '') + info.content; + } + } + // 不在收集思考内容,正常追加 + else { + msg.content += info.content; + } } // 批量处理其他属性,只有当属性值不为null/undefined且不为空字符串时才更新 diff --git a/web/src/components/MessageComponent.vue b/web/src/components/MessageComponent.vue index a2ed96bc3..858b61e06 100644 --- a/web/src/components/MessageComponent.vue +++ b/web/src/components/MessageComponent.vue @@ -15,7 +15,7 @@ -

{{ message.reasoning_content }}

+

{{ message.reasoning_content.trim() }}

@@ -56,7 +56,7 @@ -
+
请求错误,请重试。{{ message.message }}
From e8b2b253f03f14aafdb3775bd479d1474b4ce5ad Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Sun, 27 Apr 2025 18:59:38 +0800 Subject: [PATCH 02/74] =?UTF-8?q?=E5=B0=86=20refs=20=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E5=88=B0=E4=BE=A7=E8=BE=B9=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/package.json | 2 +- web/src/components/ChatComponent.vue | 85 ++++- web/src/components/GraphContainer.vue | 153 ++++++++- web/src/components/MessageComponent.vue | 9 +- web/src/components/RefsComponent.vue | 321 ++---------------- web/src/components/RefsSidebar.vue | 426 ++++++++++++++++++++++++ 6 files changed, 689 insertions(+), 307 deletions(-) create mode 100644 web/src/components/RefsSidebar.vue diff --git a/web/package.json b/web/package.json index 2a496842d..157f14bbe 100644 --- a/web/package.json +++ b/web/package.json @@ -26,7 +26,7 @@ "less": "^4.1.3", "marked": "^13.0.2", "marked-highlight": "^2.1.4", - "md-editor-v3": "^4.16.7", + "md-editor-v3": "^4.21.3", "pinia": "^2.0.32", "vue": "^3.5.13", "vue-router": "^4.1.6" diff --git a/web/src/components/ChatComponent.vue b/web/src/components/ChatComponent.vue index a4fe2578e..3e1737f99 100644 --- a/web/src/components/ChatComponent.vue +++ b/web/src/components/ChatComponent.vue @@ -81,13 +81,15 @@
@@ -142,6 +144,13 @@

请注意辨别内容的可靠性 By {{ configStore.config?.model_provider }}: {{ configStore.config?.model_name }}

+ + @@ -178,6 +187,7 @@ import { useConfigStore } from '@/stores/config' import { message } from 'ant-design-vue' import MessageInputComponent from '@/components/MessageInputComponent.vue' import MessageComponent from '@/components/MessageComponent.vue' +import RefsSidebar from '@/components/RefsSidebar.vue' const props = defineProps({ conv: Object, @@ -222,6 +232,41 @@ const meta = reactive(JSON.parse(localStorage.getItem('meta')) || { wideScreen: false, }) +// 添加全局refs状态 +const refsSidebarVisible = ref(false) +const currentRefs = ref({}) + +// 处理打开refs侧边栏 +const handleOpenRefs = ({ type, refs }) => { + console.log('ChatComponent handleOpenRefs called with type:', type); + console.log('Refs data structure:', JSON.stringify(refs)); + + // 先更新引用数据,确保数据在设置标签页之前已更新 + currentRefs.value = Object.assign({}, refs); + + // 强制在下一个tick更新,确保数据已经被正确应用 + nextTick(() => { + // 显示抽屉 + refsSidebarVisible.value = true; + + // 再次检查引用是否正确 + console.log('Updated refs data:', JSON.stringify(currentRefs.value)); + + // 根据type自动选择标签页 + if (refsSidebarRef.value) { + console.log('Setting active tab to:', type); + // 延迟50毫秒设置标签页,确保抽屉已打开 + setTimeout(() => { + refsSidebarRef.value.setActiveTab(type); + }, 50); + } else { + console.error('refsSidebarRef is not available'); + } + }); +} + +// 添加对RefsSidebar的ref +const refsSidebarRef = ref(null) const consoleMsg = (msg) => console.log(msg) onClickOutside(panel, () => setTimeout(() => opts.showPanel = false, 30)) @@ -358,6 +403,11 @@ const updateMessage = (info) => { propertiesToUpdate.forEach(prop => { if (info[prop] != null && (typeof info[prop] !== 'string' || info[prop] !== '')) { msg[prop] = info[prop]; + + // 如果更新了refs,同时更新全局refs + if (prop === 'refs' && info.refs) { + currentRefs.value = info.refs; + } } }); @@ -446,6 +496,12 @@ const fetchChatResponse = (user_input, cur_res_id) => { console.log(msg) groupRefs(cur_res_id); updateMessage({showThinking: "no", id: cur_res_id}); + // 更新全局refs为最新消息的refs + if (msg && msg.refs) { + // 深拷贝refs以确保不会出现引用问题 + currentRefs.value = JSON.parse(JSON.stringify(msg.refs)); + console.log('Updated currentRefs on response completion:', currentRefs.value); + } isStreaming.value = false; if (conv.value.messages.length === 2) { renameTitle(); } return; @@ -571,6 +627,11 @@ onMounted(() => { const parsedMeta = JSON.parse(storedMeta); Object.assign(meta, parsedMeta); } + + // 检查refsSidebarRef是否正确挂载 + nextTick(() => { + console.log('Is refsSidebarRef mounted?', !!refsSidebarRef.value); + }); }); onUnmounted(() => { @@ -642,6 +703,26 @@ const selectModel = (provider, name) => { configStore.setConfigValue('model_name', name) // message.success(`已切换到模型: ${name} | ${provider}`) } + +// 判断是否是最新的助手消息 +const isLatestMessage = (index) => { + // 找到最后一条助手消息的索引 + const lastAssistantMsgIndex = findLastIndex(conv.value.messages, + msg => (msg.role === 'received' || msg.role === 'assistant') && msg.status === 'finished'); + + // 如果当前索引等于最后一条助手消息的索引,则为最新消息 + return index === lastAssistantMsgIndex; +} + +// 辅助函数:从后向前查找满足条件的元素索引 +const findLastIndex = (array, predicate) => { + for (let i = array.length - 1; i >= 0; i--) { + if (predicate(array[i])) { + return i; + } + } + return -1; +} \ No newline at end of file diff --git a/web/src/components/RefsSidebar.vue b/web/src/components/RefsSidebar.vue new file mode 100644 index 000000000..773b684eb --- /dev/null +++ b/web/src/components/RefsSidebar.vue @@ -0,0 +1,426 @@ + + + + + \ No newline at end of file From be0801dce80f124ec65d01bbf44c50fb4cf97625 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Mon, 28 Apr 2025 22:53:13 +0800 Subject: [PATCH 03/74] env update --- .python-version | 1 + docker-compose.yml | 131 + docker/api.Dockerfile | 9 +- ...ker-compose.dev.yml => docker-compose.yml} | 2 +- docker/web.Dockerfile | 3 +- pyproject.toml | 33 + server/main.py | 2 +- src/config/__init__.py | 3 - src/core/graphbase.py | 4 +- web/pnpm-lock.yaml | 4214 +++++++++++++++++ 10 files changed, 4391 insertions(+), 11 deletions(-) create mode 100644 .python-version create mode 100644 docker-compose.yml rename docker/{docker-compose.dev.yml => docker-compose.yml} (99%) create mode 100644 pyproject.toml create mode 100644 web/pnpm-lock.yaml diff --git a/.python-version b/.python-version new file mode 100644 index 000000000..2c0733315 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..9b620cd4b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,131 @@ +services: + api: + build: + context: . + dockerfile: docker/api.Dockerfile + container_name: api-dev + working_dir: /app + volumes: + - ./server:/app/server + - ./src:/app/src + - ./saves_dev:/app/saves + # - ${MODEL_DIR}:/models # 如果出现 undefined volume MODEL_DIR: invalid compose project,请添加此环境变量或者注释此行 + ports: + - "5050:5050" + networks: + - app-network + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + - NEO4J_URI=bolt://graph:7687 + - NEO4J_USERNAME=neo4j + - NEO4J_PASSWORD=0123456789 + - MILVUS_URI=http://milvus:19530 + - MODEL_DIR=/models # 优先级高于 .env 中的 MODEL_DIR + - RUNNING_IN_DOCKER=true + command: uvicorn server.main:app --host 0.0.0.0 --port 5050 --reload + + web: + build: + context: . + dockerfile: docker/web.Dockerfile + target: development + container_name: web-dev + volumes: + - ./web:/app + - /app/node_modules + ports: + - "5173:5173" + depends_on: + - api + networks: + - app-network + environment: + - NODE_ENV=development + - VITE_API_URL=http://api:5050 # 添加这行 + command: pnpm run server + + graph: + image: neo4j:5.26 + container_name: graph-dev + ports: + - "7474:7474" + - "7687:7687" + volumes: + - ./volumes/neo4j/data:/data + - ./volumes/neo4j/logs:/var/lib/neo4j/logs + environment: + - NEO4J_AUTH=neo4j/0123456789 + - NEO4J_server_bolt_listen__address=0.0.0.0:7687 + - NEO4J_server_http_listen__address=0.0.0.0:7474 + - ENTITY_EMBEDDING=true + networks: + - app-network + + etcd: + container_name: milvus-etcd-dev + image: quay.io/coreos/etcd:v3.5.5 + environment: + - ETCD_AUTO_COMPACTION_MODE=revision + - ETCD_AUTO_COMPACTION_RETENTION=1000 + - ETCD_QUOTA_BACKEND_BYTES=4294967296 + - ETCD_SNAPSHOT_COUNT=50000 + volumes: + - ./volumes/milvus/etcd:/etcd + command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd + healthcheck: + test: ["CMD", "etcdctl", "endpoint", "health"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - app-network + + minio: + container_name: milvus-minio-dev + image: minio/minio:RELEASE.2023-03-20T20-16-18Z + environment: + MINIO_ACCESS_KEY: minioadmin + MINIO_SECRET_KEY: minioadmin + volumes: + - ./volumes/milvus/minio:/minio_data + command: minio server /minio_data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - app-network + + milvus: + image: milvusdb/milvus:v2.5.6 + container_name: milvus-standalone-dev + command: ["milvus", "run", "standalone"] + security_opt: + - seccomp:unconfined + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + MILVUS_LOG_LEVEL: error # Add this line to reduce log output + volumes: + - ./volumes/milvus/milvus:/var/lib/milvus + - ./volumes/milvus/logs:/var/lib/milvus/logs + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] + interval: 30s + start_period: 90s + timeout: 20s + retries: 3 + ports: + - "19530:19530" + - "9091:9091" + depends_on: + - "etcd" + - "minio" + networks: + - app-network + +networks: + app-network: + driver: bridge diff --git a/docker/api.Dockerfile b/docker/api.Dockerfile index 2bd86612a..080582c83 100644 --- a/docker/api.Dockerfile +++ b/docker/api.Dockerfile @@ -5,11 +5,14 @@ FROM python:3.12 WORKDIR /app # 复制 requirements.txt 文件(这一步如果文件没变,Docker 会使用缓存) -COPY ../requirements.txt /app/requirements.txt +# COPY../requirements.txt /app/requirements.txt +COPY ../pyproject.toml /app/pyproject.toml +COPY ../uv.lock /app/uv.lock +COPY ../.python-version /app/.python-version # 安装依赖(Docker 会缓存这一步,除非 requirements.txt 发生变化) -RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple -RUN pip install -U gunicorn -i https://pypi.tuna.tsinghua.edu.cn/simple +RUN pip install uv +RUN uv sync RUN apt-get clean RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.yml similarity index 99% rename from docker/docker-compose.dev.yml rename to docker/docker-compose.yml index 59801e343..a9b5a0c50 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.yml @@ -43,7 +43,7 @@ services: environment: - NODE_ENV=development - VITE_API_URL=http://api:5050 # 添加这行 - command: npm run server + command: pnpm run server graph: image: neo4j:5.26 diff --git a/docker/web.Dockerfile b/docker/web.Dockerfile index 20737eb39..472bffab8 100644 --- a/docker/web.Dockerfile +++ b/docker/web.Dockerfile @@ -6,7 +6,8 @@ WORKDIR /app COPY ./web/package*.json ./ # 安装依赖 -RUN npm install --verbose --force +RUN npm install -g pnpm@latest-10 +RUN pnpm install # RUN npm install --registry http://mirrors.cloud.tencent.com/npm/ --verbose --force # 复制源代码 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..64cc709b1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,33 @@ +[project] +name = "yuxi-know" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "dashscope>=1.23.2", + "docx2txt>=0.9", + "fastapi>=0.115.12", + "flagembedding>=1.3.4", + "langchain-community>=0.3.22", + "langchain-openai>=0.3.14", + "langgraph>=0.3.34", + "langsmith>=0.3.37", + "llama-index>=0.12.33", + "llama-index-readers-file>=0.4.7", + "neo4j>=5.28.1", + "openai>=1.76.0", + "opencv-python-headless>=4.11.0.86", + "paddleocr>=2.10.0", + "pymilvus>=2.5.8", + "pymupdf>=1.25.5", + "python-dotenv>=1.1.0", + "python-multipart>=0.0.20", + "pyyaml>=6.0.2", + "qianfan>=0.4.12.3", + "rapidocr-onnxruntime>=1.4.4", + "sentencepiece>=0.2.0", + "tavily-python>=0.7.0", + "uvicorn[standard]>=0.34.2", + "zhipuai>=2.1.5.20250421", +] diff --git a/server/main.py b/server/main.py index 1d1444599..93277ccf1 100644 --- a/server/main.py +++ b/server/main.py @@ -20,5 +20,5 @@ if __name__ == "__main__": - uvicorn.run(app, host="0.0.0.0", port=5000, threads=10, workers=10) + uvicorn.run(app, host="0.0.0.0", port=5050, threads=10, workers=10, reload=True) diff --git a/src/config/__init__.py b/src/config/__init__.py index c44df2547..b0df13178 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -192,9 +192,6 @@ def load(self): else: logger.warning(f"Unknown config file type {self.filename}") - else: - logger.warning(f"\n\n{'='*70}\n{'Config file not found':^70}\n{'You can custum your config in `' + self.filename + '`':^70}\n{'='*70}\n\n") - def save(self): logger.info(f"Saving config to {self.filename}") if self.filename is None: diff --git a/src/core/graphbase.py b/src/core/graphbase.py index 3862312ff..7f94e8520 100644 --- a/src/core/graphbase.py +++ b/src/core/graphbase.py @@ -26,7 +26,7 @@ def __init__(self): # 尝试加载已保存的图数据库信息 if not self.load_graph_info(): - logger.info(f"未找到已保存的图数据库信息,将创建新的配置") + logger.debug(f"未找到已保存的图数据库信息,将创建新的配置") self.start() @@ -516,7 +516,7 @@ def load_graph_info(self): try: info_file_path = os.path.join(self.work_dir, "graph_info.json") if not os.path.exists(info_file_path): - logger.warning(f"图数据库信息文件不存在:{info_file_path}") + logger.debug(f"图数据库信息文件不存在:{info_file_path}") return False with open(info_file_path, 'r', encoding='utf-8') as f: diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml new file mode 100644 index 000000000..e2a7cc4d5 --- /dev/null +++ b/web/pnpm-lock.yaml @@ -0,0 +1,4214 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@ant-design/icons-vue': + specifier: ^6.1.0 + version: 6.1.0(vue@3.5.13) + '@antv/g6': + specifier: ^5.0.17 + version: 5.0.45(workerize-loader@2.0.2(webpack@5.99.7)) + '@vueuse/core': + specifier: ^10.11.0 + version: 10.11.1(vue@3.5.13) + ant-design-vue: + specifier: ^4.2.3 + version: 4.2.6(vue@3.5.13) + ant-design-x-vue: + specifier: ^1.0.6 + version: 1.1.1(ant-design-vue@4.2.6(vue@3.5.13))(vue@3.5.13) + axios: + specifier: ^1.3.4 + version: 1.9.0 + d3: + specifier: ^7.8.3 + version: 7.9.0 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 + echarts: + specifier: ^5.4.2 + version: 5.6.0 + echarts-gl: + specifier: ^2.0.9 + version: 2.0.9(echarts@5.6.0) + highlight.js: + specifier: ^11.10.0 + version: 11.11.1 + less: + specifier: ^4.1.3 + version: 4.3.0 + marked: + specifier: ^13.0.2 + version: 13.0.3 + marked-highlight: + specifier: ^2.1.4 + version: 2.2.1(marked@13.0.3) + md-editor-v3: + specifier: ^4.21.3 + version: 4.21.3(vue@3.5.13) + pinia: + specifier: ^2.0.32 + version: 2.3.1(vue@3.5.13) + vue: + specifier: ^3.5.13 + version: 3.5.13 + vue-router: + specifier: ^4.1.6 + version: 4.5.1(vue@3.5.13) + devDependencies: + '@rushstack/eslint-patch': + specifier: ^1.2.0 + version: 1.11.0 + '@vitejs/plugin-vue': + specifier: ^4.0.0 + version: 4.6.2(vite@4.5.13(@types/node@22.15.3)(less@4.3.0)(terser@5.39.0))(vue@3.5.13) + '@vue/eslint-config-prettier': + specifier: ^7.1.0 + version: 7.1.0(eslint@9.25.1)(prettier@2.8.8) + eslint: + specifier: ^9.15.0 + version: 9.25.1 + eslint-plugin-vue: + specifier: ^9.9.0 + version: 9.33.0(eslint@9.25.1) + prettier: + specifier: ^2.8.4 + version: 2.8.8 + vite: + specifier: ^4.1.4 + version: 4.5.13(@types/node@22.15.3)(less@4.3.0)(terser@5.39.0) + +packages: + + '@ant-design/colors@6.0.0': + resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==} + + '@ant-design/fast-color@2.0.6': + resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} + engines: {node: '>=8.x'} + + '@ant-design/icons-svg@4.4.2': + resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} + + '@ant-design/icons-vue@6.1.0': + resolution: {integrity: sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==} + peerDependencies: + vue: '>=3.0.3' + + '@ant-design/icons-vue@7.0.1': + resolution: {integrity: sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==} + peerDependencies: + vue: '>=3.0.3' + + '@antv/algorithm@0.1.26': + resolution: {integrity: sha512-DVhcFSQ8YQnMNW34Mk8BSsfc61iC1sAnmcfYoXTAshYHuU50p/6b7x3QYaGctDNKWGvi1ub7mPcSY0bK+aN0qg==} + + '@antv/component@2.1.2': + resolution: {integrity: sha512-5nC9i9lh5rBHE+pk4TNnerLe4mn5874YHHhvv6EdL618UkgpdKJL0hJu4l7uAYjZ3g46VBK+IYT7md0FYv8f4w==} + + '@antv/event-emitter@0.1.3': + resolution: {integrity: sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==} + + '@antv/g-camera-api@2.0.37': + resolution: {integrity: sha512-LfNurM/DZirouy8nu69xm+x8EjhT/WmZmaBKBu1ku5pTY52KLBQC0gFQMZ3L8fjUMcmhEtwcRY7wyIG3yDIoTg==} + + '@antv/g-canvas@2.0.42': + resolution: {integrity: sha512-RAe7AcrequkVRopzXWoIK+w/UQhtzDgh9YFCO8sjmuYNyw5rZfg1ZD7m+EPE3g9X7S9aV5qxfav63beUuihSiw==} + + '@antv/g-dom-mutation-observer-api@2.0.34': + resolution: {integrity: sha512-oNBGtwEuV0+FFk8NCCKxK13V2FJdzIgyC7XSAjtVUR5P2/tgZqNEaOEz6byrimZsft2dZsQUyjl17QSooLRkMw==} + + '@antv/g-lite@2.2.18': + resolution: {integrity: sha512-m7Oq0cXF5rOSKYpgZwP99b4165WXLePsyG4mX7oUWqL0cEweafk+92Re7tSSnvhUBhgmM7rJ5X1AipFnpzt0Kw==} + + '@antv/g-math@3.0.0': + resolution: {integrity: sha512-AkmiNIEL1vgqTPeGY2wtsMdBBqKFwF7SKSgs+D1iOS/rqYMsXdhp/HvtuQ5tx/HdawE/ZzTiicIYopc520ADZw==} + + '@antv/g-plugin-canvas-path-generator@2.1.18': + resolution: {integrity: sha512-TOfWb13diw/yMcmYpgDYqXtPFMdw6ywcykJ8WIvW0MjJEjM/HGNmmoVbJYZWTipEm9MwAp38eomhPQS7FeohWQ==} + + '@antv/g-plugin-canvas-picker@2.1.21': + resolution: {integrity: sha512-C27pcYeXygltMrLtTxkUiELusgPaVBM9t2nXV+Szldp7K0uOXWSmNfjq3zVcRBMecvKTLdFV8Vz6fk6JxMtmqA==} + + '@antv/g-plugin-canvas-renderer@2.2.21': + resolution: {integrity: sha512-WcemVy8BcSMA6Nf7MeLaj0OVjgwGnl5dvIXY0TmwRuvsQiRRWYtKNPFuSjADQ+AEVmUUsPwTn5R2YRH0SDY72w==} + + '@antv/g-plugin-dom-interaction@2.1.23': + resolution: {integrity: sha512-wcVoB37tZmv3zo2VSLiGitND7+WuKBIYc8mQG3etR48Dk67l+Z0lJa8HUqjdp47blI7nOYF4AP9d2SjI5LQ1sw==} + + '@antv/g-plugin-dragndrop@2.0.34': + resolution: {integrity: sha512-XO/nSAZiiZkzJcw4wInyw4uwaxCL08jJTyVWwdh+n6++R9DUTbwRE72jdoX5KmY8ykO7dtbNWEF9GA0ldBqNIw==} + + '@antv/g-plugin-html-renderer@2.1.23': + resolution: {integrity: sha512-G3m7yIkl/p1hShO5X9r1RTPUVl4XkU72agvQZzvv0oWy+PkYzrlA7duzVz/4Jh7kkOiAnfV6NqxMWrldvJAT+A==} + + '@antv/g-plugin-image-loader@2.1.21': + resolution: {integrity: sha512-hz0VphH4f16e61eKbMvFPhyM7yH9XyU9aLcYcs6WGbu+kZ2v4kc7wlefbER41dqGbEy7GG0qDvQczDiRbrWYQg==} + + '@antv/g-web-animations-api@2.1.23': + resolution: {integrity: sha512-gpXdxAbVtcM+SOsoc0ucPba7cWgG6FEp2EWGuaMzOiqoJGplp511xZ+d9T3l9hgp/vWOSKt/NZ9PlOPqXSK2GA==} + + '@antv/g6@5.0.45': + resolution: {integrity: sha512-gwJnan63G+UOyoGAFRafEJjcFHVDt2MPM7xpryJd3Pg0uAFTBQSAriqfNecNj7Ao9vDwfkcrfP5sN87yksMSfA==} + + '@antv/g@6.1.23': + resolution: {integrity: sha512-D3t5gNV5ci3okmkF9N03lZ7arheYE/KmaXBTEuEFWxLOJPsGjweVcM+cNJJ6o0pc+4toGz+XpPFB/Xvz2gM5tw==} + + '@antv/graphlib@2.0.4': + resolution: {integrity: sha512-zc/5oQlsdk42Z0ib1mGklwzhJ5vczLFiPa1v7DgJkTbgJ2YxRh9xdarf86zI49sKVJmgbweRpJs7Nu5bIiwv4w==} + + '@antv/hierarchy@0.6.14': + resolution: {integrity: sha512-V3uknf7bhynOqQDw2sg+9r9DwZ9pc6k/EcqyTFdfXB1+ydr7urisP0MipIuimucvQKN+Qkd+d6w601r1UIroqQ==} + + '@antv/layout@1.2.14-beta.9': + resolution: {integrity: sha512-wPlwBFMtq2lWZFc89/7Lzb8fjHnyKVZZ9zBb2h+zZIP0YWmVmHRE8+dqCiPKOyOGUXEdDtn813f1g107dCHZlg==} + + '@antv/scale@0.4.16': + resolution: {integrity: sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw==} + + '@antv/util@2.0.17': + resolution: {integrity: sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==} + + '@antv/util@3.3.10': + resolution: {integrity: sha512-basGML3DFA3O87INnzvDStjzS+n0JLEhRnRsDzP9keiXz8gT1z/fTdmJAZFOzMMWxy+HKbi7NbSt0+8vz/OsBQ==} + + '@antv/vendor@1.0.11': + resolution: {integrity: sha512-LmhPEQ+aapk3barntaiIxJ5VHno/Tyab2JnfdcPzp5xONh/8VSfed4bo/9xKo5HcUAEydko38vYLfj6lJliLiw==} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.27.0': + resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.27.0': + resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.27.0': + resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} + engines: {node: '>=6.9.0'} + + '@codemirror/autocomplete@6.18.6': + resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==} + + '@codemirror/commands@6.8.1': + resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==} + + '@codemirror/lang-angular@0.1.4': + resolution: {integrity: sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g==} + + '@codemirror/lang-cpp@6.0.2': + resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==} + + '@codemirror/lang-css@6.3.1': + resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==} + + '@codemirror/lang-go@6.0.1': + resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==} + + '@codemirror/lang-html@6.4.9': + resolution: {integrity: sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==} + + '@codemirror/lang-java@6.0.1': + resolution: {integrity: sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==} + + '@codemirror/lang-javascript@6.2.3': + resolution: {integrity: sha512-8PR3vIWg7pSu7ur8A07pGiYHgy3hHj+mRYRCSG8q+mPIrl0F02rgpGv+DsQTHRTc30rydOsf5PZ7yjKFg2Ackw==} + + '@codemirror/lang-json@6.0.1': + resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==} + + '@codemirror/lang-less@6.0.2': + resolution: {integrity: sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ==} + + '@codemirror/lang-liquid@6.2.3': + resolution: {integrity: sha512-yeN+nMSrf/lNii3FJxVVEGQwFG0/2eDyH6gNOj+TGCa0hlNO4bhQnoO5ISnd7JOG+7zTEcI/GOoyraisFVY7jQ==} + + '@codemirror/lang-markdown@6.3.2': + resolution: {integrity: sha512-c/5MYinGbFxYl4itE9q/rgN/sMTjOr8XL5OWnC+EaRMLfCbVUmmubTJfdgpfcSS2SCaT7b+Q+xi3l6CgoE+BsA==} + + '@codemirror/lang-php@6.0.1': + resolution: {integrity: sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==} + + '@codemirror/lang-python@6.2.0': + resolution: {integrity: sha512-+oLTR88uLib84tvb4XmOBBq/dgrctvPXueP3Wjotu4zmHLM2KW2wfswJ6r1BKlfJNcGgdWX1AgUeGEf3E2H5LA==} + + '@codemirror/lang-rust@6.0.1': + resolution: {integrity: sha512-344EMWFBzWArHWdZn/NcgkwMvZIWUR1GEBdwG8FEp++6o6vT6KL9V7vGs2ONsKxxFUPXKI0SPcWhyYyl2zPYxQ==} + + '@codemirror/lang-sass@6.0.2': + resolution: {integrity: sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==} + + '@codemirror/lang-sql@6.8.0': + resolution: {integrity: sha512-aGLmY4OwGqN3TdSx3h6QeA1NrvaYtF7kkoWR/+W7/JzB0gQtJ+VJxewlnE3+VImhA4WVlhmkJr109PefOOhjLg==} + + '@codemirror/lang-vue@0.1.3': + resolution: {integrity: sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==} + + '@codemirror/lang-wast@6.0.2': + resolution: {integrity: sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q==} + + '@codemirror/lang-xml@6.1.0': + resolution: {integrity: sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==} + + '@codemirror/lang-yaml@6.1.2': + resolution: {integrity: sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==} + + '@codemirror/language-data@6.5.1': + resolution: {integrity: sha512-0sWxeUSNlBr6OmkqybUTImADFUP0M3P0IiSde4nc24bz/6jIYzqYSgkOSLS+CBIoW1vU8Q9KUWXscBXeoMVC9w==} + + '@codemirror/language@6.11.0': + resolution: {integrity: sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==} + + '@codemirror/legacy-modes@6.5.1': + resolution: {integrity: sha512-DJYQQ00N1/KdESpZV7jg9hafof/iBNp9h7TYo1SLMk86TWl9uDsVdho2dzd81K+v4retmK6mdC7WpuOQDytQqw==} + + '@codemirror/lint@6.8.5': + resolution: {integrity: sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==} + + '@codemirror/search@6.5.10': + resolution: {integrity: sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg==} + + '@codemirror/state@6.5.2': + resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} + + '@codemirror/view@6.36.6': + resolution: {integrity: sha512-uxugGLet+Nzp0Jcit8Hn3LypM8ioMLKTsdf8FRoT3HWvZtb9GhaWMe0Cc15rz90Ljab4YFJiAulmIVB74OY0IQ==} + + '@ctrl/tinycolor@3.6.1': + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/unitless@0.8.1': + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.18.20': + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.18.20': + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.18.20': + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.18.20': + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.18.20': + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.18.20': + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.18.20': + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.18.20': + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.6.1': + resolution: {integrity: sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.20.0': + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.2.1': + resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.13.0': + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.25.1': + resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.8': + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.2': + resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@lezer/common@1.2.3': + resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + + '@lezer/cpp@1.1.3': + resolution: {integrity: sha512-ykYvuFQKGsRi6IcE+/hCSGUhb/I4WPjd3ELhEblm2wS2cOznDFzO+ubK2c+ioysOnlZ3EduV+MVQFCPzAIoY3w==} + + '@lezer/css@1.1.11': + resolution: {integrity: sha512-FuAnusbLBl1SEAtfN8NdShxYJiESKw9LAFysfea1T96jD3ydBn12oYjaSG1a04BQRIUd93/0D8e5CV1cUMkmQg==} + + '@lezer/go@1.0.0': + resolution: {integrity: sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==} + + '@lezer/highlight@1.2.1': + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + + '@lezer/html@1.3.10': + resolution: {integrity: sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==} + + '@lezer/java@1.1.3': + resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==} + + '@lezer/javascript@1.5.1': + resolution: {integrity: sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==} + + '@lezer/json@1.0.3': + resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} + + '@lezer/lr@1.4.2': + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + + '@lezer/markdown@1.4.3': + resolution: {integrity: sha512-kfw+2uMrQ/wy/+ONfrH83OkdFNM0ye5Xq96cLlaCy7h5UT9FO54DU4oRoIc0CSBh5NWmWuiIJA7NGLMJbQ+Oxg==} + + '@lezer/php@1.0.2': + resolution: {integrity: sha512-GN7BnqtGRpFyeoKSEqxvGvhJQiI4zkgmYnDk/JIyc7H7Ifc1tkPnUn/R2R8meH3h/aBf5rzjvU8ZQoyiNDtDrA==} + + '@lezer/python@1.1.18': + resolution: {integrity: sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==} + + '@lezer/rust@1.0.2': + resolution: {integrity: sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==} + + '@lezer/sass@1.0.7': + resolution: {integrity: sha512-8HLlOkuX/SMHOggI2DAsXUw38TuURe+3eQ5hiuk9QmYOUyC55B1dYEIMkav5A4IELVaW4e1T4P9WRiI5ka4mdw==} + + '@lezer/xml@1.0.6': + resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==} + + '@lezer/yaml@1.0.3': + resolution: {integrity: sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==} + + '@marijn/find-cluster-break@1.0.2': + resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + + '@naoak/workerize-transferable@0.1.0': + resolution: {integrity: sha512-fDLfuP71IPNP5+zSfxFb52OHgtjZvauRJWbVnpzQ7G7BjcbLjTny0OW1d3ZO806XKpLWNKmeeW3MhE0sy8iwYQ==} + peerDependencies: + workerize-loader: '*' + + '@rushstack/eslint-patch@1.11.0': + resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==} + + '@simonwep/pickr@1.8.2': + resolution: {integrity: sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==} + + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-dispatch@3.0.6': + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/node@22.15.3': + resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} + + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@vavt/util@2.1.0': + resolution: {integrity: sha512-YIfAvArSFVXmWvoF+DEGD0FhkhVNcCtVWWkfYtj76eSrwHh/wuEEFhiEubg1XLNM3tChO8FH8xJCT/hnizjgFQ==} + + '@vitejs/plugin-vue@4.6.2': + resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 || ^5.0.0 + vue: ^3.2.25 + + '@vue/compiler-core@3.5.13': + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + + '@vue/compiler-dom@3.5.13': + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + + '@vue/compiler-sfc@3.5.13': + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + + '@vue/compiler-ssr@3.5.13': + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/eslint-config-prettier@7.1.0': + resolution: {integrity: sha512-Pv/lVr0bAzSIHLd9iz0KnvAr4GKyCEl+h52bc4e5yWuDVtLgFwycF7nrbWTAQAS+FU6q1geVd07lc6EWfJiWKQ==} + peerDependencies: + eslint: '>= 7.28.0' + prettier: '>= 2.0.0' + + '@vue/reactivity@3.5.13': + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + + '@vue/runtime-core@3.5.13': + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + + '@vue/runtime-dom@3.5.13': + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + + '@vue/server-renderer@3.5.13': + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + peerDependencies: + vue: 3.5.13 + + '@vue/shared@3.5.13': + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + + '@vueuse/core@10.11.1': + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + + '@vueuse/metadata@10.11.1': + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} + + '@vueuse/shared@10.11.1': + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ant-design-vue@4.2.6: + resolution: {integrity: sha512-t7eX13Yj3i9+i5g9lqFyYneoIb3OzTvQjq9Tts1i+eiOd3Eva/6GagxBSXM1fOCjqemIu0FYVE1ByZ/38epR3Q==} + engines: {node: '>=12.22.0'} + peerDependencies: + vue: '>=3.2.0' + + ant-design-x-vue@1.1.1: + resolution: {integrity: sha512-ZnxWxmfY6gyESxwtWM6OJNRmnn3fDR9fM55lrb48vOVa45KFdl++TsAJ+C+5BYx+8nP6x9OZDmjD+RAQ/J8L8Q==} + peerDependencies: + ant-design-vue: '>=4.0.0' + vue: '>=3.5.0' + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-tree-filter@2.1.0: + resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} + + async-validator@4.2.5: + resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.9.0: + resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + big.js@5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bubblesets-js@2.3.4: + resolution: {integrity: sha512-DyMjHmpkS2+xcFNtyN00apJYL3ESdp9fTrkDr5+9Qg/GPqFmcWgGsK1akZnttE1XFxJ/VMy4DNNGMGYtmFp1Sg==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001715: + resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + + claygl@1.3.0: + resolution: {integrity: sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==} + + codemirror@6.0.1: + resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + comlink@4.4.2: + resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + + core-js@3.41.0: + resolution: {integrity: sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssfilter@0.0.10: + resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-binarytree@1.0.2: + resolution: {integrity: sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force-3d@3.0.6: + resolution: {integrity: sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo-projection@4.0.0: + resolution: {integrity: sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==} + engines: {node: '>=12'} + hasBin: true + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-octree@1.1.0: + resolution: {integrity: sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-regression@1.3.10: + resolution: {integrity: sha512-PF8GWEL70cHHWpx2jUQXc68r1pyPHIA+St16muk/XRokETzlegj5LriNKg7o4LR0TySug4nHYPJNNRz/W+/Niw==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre@0.8.5: + resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dom-align@1.12.4: + resolution: {integrity: sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==} + + dom-scroll-into-view@2.0.1: + resolution: {integrity: sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + echarts-gl@2.0.9: + resolution: {integrity: sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==} + peerDependencies: + echarts: ^5.1.2 + + echarts@5.6.0: + resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==} + + electron-to-chromium@1.5.143: + resolution: {integrity: sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g==} + + emojis-list@3.0.0: + resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} + engines: {node: '>= 4'} + + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@8.10.0: + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-prettier@4.2.1: + resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: '>=7.28.0' + eslint-config-prettier: '*' + prettier: '>=2.0.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + + eslint-plugin-vue@9.33.0: + resolution: {integrity: sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.25.1: + resolution: {integrity: sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + engines: {node: '>= 6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + gl-matrix@3.4.3: + resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphlib@2.1.8: + resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + highlight.js@11.11.1: + resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} + engines: {node: '>=12.0.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + is-any-array@2.0.1: + resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==} + + is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-plain-object@3.0.1: + resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} + engines: {node: '>=0.10.0'} + + is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + less@4.3.0: + resolution: {integrity: sha512-X9RyH9fvemArzfdP8Pi3irr7lor2Ok4rOttDXBhlwDg+wKQsXOXgHWduAJE1EsF7JJx0w0bcO6BC6tCKKYnXKA==} + engines: {node: '>=14'} + hasBin: true + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + loader-utils@2.0.4: + resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} + engines: {node: '>=8.9.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + + markdown-it-image-figures@2.1.1: + resolution: {integrity: sha512-mwXSQ2nPeVUzCMIE3HlLvjRioopiqyJLNph0pyx38yf9mpqFDhNGnMpAXF9/A2Xv0oiF2cVyg9xwfF0HNAz05g==} + engines: {node: '>=12.0.0'} + peerDependencies: + markdown-it: '*' + + markdown-it-sub@2.0.0: + resolution: {integrity: sha512-iCBKgwCkfQBRg2vApy9vx1C1Tu6D8XYo8NvevI3OlwzBRmiMtsJ2sXupBgEA7PPxiDwNni3qIUkhZ6j5wofDUA==} + + markdown-it-sup@2.0.0: + resolution: {integrity: sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + marked-highlight@2.2.1: + resolution: {integrity: sha512-SiCIeEiQbs9TxGwle9/OwbOejHCZsohQRaNTY2u8euEXYt2rYUFoiImUirThU3Gd/o6Q1gHGtH9qloHlbJpNIA==} + peerDependencies: + marked: '>=4 <16' + + marked@13.0.3: + resolution: {integrity: sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==} + engines: {node: '>= 18'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md-editor-v3@4.21.3: + resolution: {integrity: sha512-9+RCioqFIWSExTsG0jf9T/RTrFhtH8SpRcKVjHeEQSlExAr/zsgYt/M9XUy/nuGx87hgNKDzK0PXp/uOlDumAw==} + peerDependencies: + vue: ^3.2.47 + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + medium-zoom@1.1.0: + resolution: {integrity: sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + ml-array-max@1.2.4: + resolution: {integrity: sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==} + + ml-array-min@1.2.3: + resolution: {integrity: sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q==} + + ml-array-rescale@1.3.7: + resolution: {integrity: sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ==} + + ml-matrix@6.12.1: + resolution: {integrity: sha512-TJ+8eOFdp+INvzR4zAuwBQJznDUfktMtOB6g/hUcGh3rcyjxbz4Te57Pgri8Q9bhSQ7Zys4IYOGhFdnlgeB6Lw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanopop@2.4.2: + resolution: {integrity: sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + needle@3.3.1: + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} + hasBin: true + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pinia@2.3.1: + resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==} + peerDependencies: + typescript: '>=4.4.4' + vue: ^2.7.0 || ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + quickselect@2.0.0: + resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + rbush@3.0.1: + resolution: {integrity: sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + + rollup@3.29.5: + resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + + schema-utils@4.3.2: + resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + engines: {node: '>= 10.13.0'} + + scroll-into-view-if-needed@2.2.31: + resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + shallow-equal@1.2.1: + resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + svg-path-parser@1.1.0: + resolution: {integrity: sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A==} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + terser-webpack-plugin@5.3.14: + resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.39.0: + resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==} + engines: {node: '>=10'} + hasBin: true + + throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} + engines: {node: '>=12.22'} + + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@4.5.13: + resolution: {integrity: sha512-Hgp8IF/yZDzKsN1hQWOuQZbrKiaFsbQud+07jJ8h9m9PaHWkpvZ5u55Xw5yYjWRXwRQ4jwFlJvY7T7FUJG9MCA==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-eslint-parser@9.4.3: + resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + + vue-router@4.5.1: + resolution: {integrity: sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==} + peerDependencies: + vue: ^3.2.0 + + vue-types@3.0.2: + resolution: {integrity: sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==} + engines: {node: '>=10.15.0'} + peerDependencies: + vue: ^3.0.0 + + vue@3.5.13: + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + + watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + engines: {node: '>=10.13.0'} + + webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + + webpack@5.99.7: + resolution: {integrity: sha512-CNqKBRMQjwcmKR0idID5va1qlhrqVUKpovi+Ec79ksW8ux7iS1+A6VqzfZXgVYCFRKl7XL5ap3ZoMpwBJxcg0w==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + workerize-loader@2.0.2: + resolution: {integrity: sha512-HoZ6XY4sHWxA2w0WpzgBwUiR3dv1oo7bS+oCwIpb6n54MclQ/7KXdXsVIChTCygyuHtVuGBO1+i3HzTt699UJQ==} + peerDependencies: + webpack: '*' + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + xss@1.0.15: + resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} + engines: {node: '>= 0.10.0'} + hasBin: true + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zrender@5.6.1: + resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==} + +snapshots: + + '@ant-design/colors@6.0.0': + dependencies: + '@ctrl/tinycolor': 3.6.1 + + '@ant-design/fast-color@2.0.6': + dependencies: + '@babel/runtime': 7.27.0 + + '@ant-design/icons-svg@4.4.2': {} + + '@ant-design/icons-vue@6.1.0(vue@3.5.13)': + dependencies: + '@ant-design/colors': 6.0.0 + '@ant-design/icons-svg': 4.4.2 + vue: 3.5.13 + + '@ant-design/icons-vue@7.0.1(vue@3.5.13)': + dependencies: + '@ant-design/colors': 6.0.0 + '@ant-design/icons-svg': 4.4.2 + vue: 3.5.13 + + '@antv/algorithm@0.1.26': + dependencies: + '@antv/util': 2.0.17 + tslib: 2.8.1 + + '@antv/component@2.1.2': + dependencies: + '@antv/g': 6.1.23 + '@antv/scale': 0.4.16 + '@antv/util': 3.3.10 + svg-path-parser: 1.1.0 + + '@antv/event-emitter@0.1.3': {} + + '@antv/g-camera-api@2.0.37': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + gl-matrix: 3.4.3 + tslib: 2.8.1 + + '@antv/g-canvas@2.0.42': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/g-plugin-canvas-path-generator': 2.1.18 + '@antv/g-plugin-canvas-picker': 2.1.21 + '@antv/g-plugin-canvas-renderer': 2.2.21 + '@antv/g-plugin-dom-interaction': 2.1.23 + '@antv/g-plugin-html-renderer': 2.1.23 + '@antv/g-plugin-image-loader': 2.1.21 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + tslib: 2.8.1 + + '@antv/g-dom-mutation-observer-api@2.0.34': + dependencies: + '@antv/g-lite': 2.2.18 + '@babel/runtime': 7.27.0 + + '@antv/g-lite@2.2.18': + dependencies: + '@antv/g-math': 3.0.0 + '@antv/util': 3.3.10 + '@antv/vendor': 1.0.11 + '@babel/runtime': 7.27.0 + eventemitter3: 5.0.1 + gl-matrix: 3.4.3 + rbush: 3.0.1 + tslib: 2.8.1 + + '@antv/g-math@3.0.0': + dependencies: + '@antv/util': 3.3.10 + gl-matrix: 3.4.3 + tslib: 2.8.1 + + '@antv/g-plugin-canvas-path-generator@2.1.18': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/g-math': 3.0.0 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + tslib: 2.8.1 + + '@antv/g-plugin-canvas-picker@2.1.21': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/g-math': 3.0.0 + '@antv/g-plugin-canvas-path-generator': 2.1.18 + '@antv/g-plugin-canvas-renderer': 2.2.21 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + gl-matrix: 3.4.3 + tslib: 2.8.1 + + '@antv/g-plugin-canvas-renderer@2.2.21': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/g-math': 3.0.0 + '@antv/g-plugin-canvas-path-generator': 2.1.18 + '@antv/g-plugin-image-loader': 2.1.21 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + gl-matrix: 3.4.3 + tslib: 2.8.1 + + '@antv/g-plugin-dom-interaction@2.1.23': + dependencies: + '@antv/g-lite': 2.2.18 + '@babel/runtime': 7.27.0 + tslib: 2.8.1 + + '@antv/g-plugin-dragndrop@2.0.34': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + tslib: 2.8.1 + + '@antv/g-plugin-html-renderer@2.1.23': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + gl-matrix: 3.4.3 + tslib: 2.8.1 + + '@antv/g-plugin-image-loader@2.1.21': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + gl-matrix: 3.4.3 + tslib: 2.8.1 + + '@antv/g-web-animations-api@2.1.23': + dependencies: + '@antv/g-lite': 2.2.18 + '@antv/util': 3.3.10 + '@babel/runtime': 7.27.0 + tslib: 2.8.1 + + '@antv/g6@5.0.45(workerize-loader@2.0.2(webpack@5.99.7))': + dependencies: + '@antv/algorithm': 0.1.26 + '@antv/component': 2.1.2 + '@antv/event-emitter': 0.1.3 + '@antv/g': 6.1.23 + '@antv/g-canvas': 2.0.42 + '@antv/g-plugin-dragndrop': 2.0.34 + '@antv/graphlib': 2.0.4 + '@antv/hierarchy': 0.6.14 + '@antv/layout': 1.2.14-beta.9(workerize-loader@2.0.2(webpack@5.99.7)) + '@antv/util': 3.3.10 + bubblesets-js: 2.3.4 + transitivePeerDependencies: + - workerize-loader + + '@antv/g@6.1.23': + dependencies: + '@antv/g-camera-api': 2.0.37 + '@antv/g-dom-mutation-observer-api': 2.0.34 + '@antv/g-lite': 2.2.18 + '@antv/g-web-animations-api': 2.1.23 + '@babel/runtime': 7.27.0 + + '@antv/graphlib@2.0.4': + dependencies: + '@antv/event-emitter': 0.1.3 + + '@antv/hierarchy@0.6.14': {} + + '@antv/layout@1.2.14-beta.9(workerize-loader@2.0.2(webpack@5.99.7))': + dependencies: + '@antv/event-emitter': 0.1.3 + '@antv/graphlib': 2.0.4 + '@antv/util': 3.3.10 + '@naoak/workerize-transferable': 0.1.0(workerize-loader@2.0.2(webpack@5.99.7)) + comlink: 4.4.2 + d3-force: 3.0.0 + d3-force-3d: 3.0.6 + d3-octree: 1.1.0 + d3-quadtree: 3.0.1 + dagre: 0.8.5 + ml-matrix: 6.12.1 + tslib: 2.8.1 + transitivePeerDependencies: + - workerize-loader + + '@antv/scale@0.4.16': + dependencies: + '@antv/util': 3.3.10 + color-string: 1.9.1 + fecha: 4.2.3 + + '@antv/util@2.0.17': + dependencies: + csstype: 3.1.3 + tslib: 2.8.1 + + '@antv/util@3.3.10': + dependencies: + fast-deep-equal: 3.1.3 + gl-matrix: 3.4.3 + tslib: 2.8.1 + + '@antv/vendor@1.0.11': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-color': 3.1.3 + '@types/d3-dispatch': 3.0.6 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-force-3d: 3.0.6 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-geo-projection: 4.0.0 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-regression: 1.3.10 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/parser@7.27.0': + dependencies: + '@babel/types': 7.27.0 + + '@babel/runtime@7.27.0': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/types@7.27.0': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@codemirror/autocomplete@6.18.6': + dependencies: + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + + '@codemirror/commands@6.8.1': + dependencies: + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + + '@codemirror/lang-angular@0.1.4': + dependencies: + '@codemirror/lang-html': 6.4.9 + '@codemirror/lang-javascript': 6.2.3 + '@codemirror/language': 6.11.0 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@codemirror/lang-cpp@6.0.2': + dependencies: + '@codemirror/language': 6.11.0 + '@lezer/cpp': 1.1.3 + + '@codemirror/lang-css@6.3.1': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@lezer/common': 1.2.3 + '@lezer/css': 1.1.11 + + '@codemirror/lang-go@6.0.1': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@lezer/common': 1.2.3 + '@lezer/go': 1.0.0 + + '@codemirror/lang-html@6.4.9': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-javascript': 6.2.3 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + '@lezer/css': 1.1.11 + '@lezer/html': 1.3.10 + + '@codemirror/lang-java@6.0.1': + dependencies: + '@codemirror/language': 6.11.0 + '@lezer/java': 1.1.3 + + '@codemirror/lang-javascript@6.2.3': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/language': 6.11.0 + '@codemirror/lint': 6.8.5 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + '@lezer/javascript': 1.5.1 + + '@codemirror/lang-json@6.0.1': + dependencies: + '@codemirror/language': 6.11.0 + '@lezer/json': 1.0.3 + + '@codemirror/lang-less@6.0.2': + dependencies: + '@codemirror/lang-css': 6.3.1 + '@codemirror/language': 6.11.0 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@codemirror/lang-liquid@6.2.3': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/lang-html': 6.4.9 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@codemirror/lang-markdown@6.3.2': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/lang-html': 6.4.9 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + '@lezer/markdown': 1.4.3 + + '@codemirror/lang-php@6.0.1': + dependencies: + '@codemirror/lang-html': 6.4.9 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@lezer/common': 1.2.3 + '@lezer/php': 1.0.2 + + '@codemirror/lang-python@6.2.0': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@lezer/common': 1.2.3 + '@lezer/python': 1.1.18 + + '@codemirror/lang-rust@6.0.1': + dependencies: + '@codemirror/language': 6.11.0 + '@lezer/rust': 1.0.2 + + '@codemirror/lang-sass@6.0.2': + dependencies: + '@codemirror/lang-css': 6.3.1 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@lezer/common': 1.2.3 + '@lezer/sass': 1.0.7 + + '@codemirror/lang-sql@6.8.0': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@codemirror/lang-vue@0.1.3': + dependencies: + '@codemirror/lang-html': 6.4.9 + '@codemirror/lang-javascript': 6.2.3 + '@codemirror/language': 6.11.0 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@codemirror/lang-wast@6.0.2': + dependencies: + '@codemirror/language': 6.11.0 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@codemirror/lang-xml@6.1.0': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + '@lezer/xml': 1.0.6 + + '@codemirror/lang-yaml@6.1.2': + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/language': 6.11.0 + '@codemirror/state': 6.5.2 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + '@lezer/yaml': 1.0.3 + + '@codemirror/language-data@6.5.1': + dependencies: + '@codemirror/lang-angular': 0.1.4 + '@codemirror/lang-cpp': 6.0.2 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-go': 6.0.1 + '@codemirror/lang-html': 6.4.9 + '@codemirror/lang-java': 6.0.1 + '@codemirror/lang-javascript': 6.2.3 + '@codemirror/lang-json': 6.0.1 + '@codemirror/lang-less': 6.0.2 + '@codemirror/lang-liquid': 6.2.3 + '@codemirror/lang-markdown': 6.3.2 + '@codemirror/lang-php': 6.0.1 + '@codemirror/lang-python': 6.2.0 + '@codemirror/lang-rust': 6.0.1 + '@codemirror/lang-sass': 6.0.2 + '@codemirror/lang-sql': 6.8.0 + '@codemirror/lang-vue': 0.1.3 + '@codemirror/lang-wast': 6.0.2 + '@codemirror/lang-xml': 6.1.0 + '@codemirror/lang-yaml': 6.1.2 + '@codemirror/language': 6.11.0 + '@codemirror/legacy-modes': 6.5.1 + + '@codemirror/language@6.11.0': + dependencies: + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + style-mod: 4.1.2 + + '@codemirror/legacy-modes@6.5.1': + dependencies: + '@codemirror/language': 6.11.0 + + '@codemirror/lint@6.8.5': + dependencies: + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + crelt: 1.0.6 + + '@codemirror/search@6.5.10': + dependencies: + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + crelt: 1.0.6 + + '@codemirror/state@6.5.2': + dependencies: + '@marijn/find-cluster-break': 1.0.2 + + '@codemirror/view@6.36.6': + dependencies: + '@codemirror/state': 6.5.2 + style-mod: 4.1.2 + w3c-keyname: 2.2.8 + + '@ctrl/tinycolor@3.6.1': {} + + '@emotion/hash@0.9.2': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/unitless@0.8.1': {} + + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/darwin-arm64@0.18.20': + optional: true + + '@esbuild/darwin-x64@0.18.20': + optional: true + + '@esbuild/freebsd-arm64@0.18.20': + optional: true + + '@esbuild/freebsd-x64@0.18.20': + optional: true + + '@esbuild/linux-arm64@0.18.20': + optional: true + + '@esbuild/linux-arm@0.18.20': + optional: true + + '@esbuild/linux-ia32@0.18.20': + optional: true + + '@esbuild/linux-loong64@0.18.20': + optional: true + + '@esbuild/linux-mips64el@0.18.20': + optional: true + + '@esbuild/linux-ppc64@0.18.20': + optional: true + + '@esbuild/linux-riscv64@0.18.20': + optional: true + + '@esbuild/linux-s390x@0.18.20': + optional: true + + '@esbuild/linux-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/openbsd-x64@0.18.20': + optional: true + + '@esbuild/sunos-x64@0.18.20': + optional: true + + '@esbuild/win32-arm64@0.18.20': + optional: true + + '@esbuild/win32-ia32@0.18.20': + optional: true + + '@esbuild/win32-x64@0.18.20': + optional: true + + '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1)': + dependencies: + eslint: 9.25.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.20.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.2.1': {} + + '@eslint/core@0.13.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.25.1': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.2.8': + dependencies: + '@eslint/core': 0.13.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.2': {} + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@lezer/common@1.2.3': {} + + '@lezer/cpp@1.1.3': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/css@1.1.11': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/go@1.0.0': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/highlight@1.2.1': + dependencies: + '@lezer/common': 1.2.3 + + '@lezer/html@1.3.10': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/java@1.1.3': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/javascript@1.5.1': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/json@1.0.3': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/lr@1.4.2': + dependencies: + '@lezer/common': 1.2.3 + + '@lezer/markdown@1.4.3': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + + '@lezer/php@1.0.2': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/python@1.1.18': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/rust@1.0.2': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/sass@1.0.7': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/xml@1.0.6': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/yaml@1.0.3': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@marijn/find-cluster-break@1.0.2': {} + + '@naoak/workerize-transferable@0.1.0(workerize-loader@2.0.2(webpack@5.99.7))': + dependencies: + workerize-loader: 2.0.2(webpack@5.99.7) + + '@rushstack/eslint-patch@1.11.0': {} + + '@simonwep/pickr@1.8.2': + dependencies: + core-js: 3.41.0 + nanopop: 2.4.2 + + '@types/d3-array@3.2.1': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-dispatch@3.0.6': {} + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.7 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.7': {} + + '@types/geojson@7946.0.16': {} + + '@types/json-schema@7.0.15': {} + + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + + '@types/node@22.15.3': + dependencies: + undici-types: 6.21.0 + + '@types/web-bluetooth@0.0.20': {} + + '@vavt/util@2.1.0': {} + + '@vitejs/plugin-vue@4.6.2(vite@4.5.13(@types/node@22.15.3)(less@4.3.0)(terser@5.39.0))(vue@3.5.13)': + dependencies: + vite: 4.5.13(@types/node@22.15.3)(less@4.3.0)(terser@5.39.0) + vue: 3.5.13 + + '@vue/compiler-core@3.5.13': + dependencies: + '@babel/parser': 7.27.0 + '@vue/shared': 3.5.13 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.13': + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/compiler-sfc@3.5.13': + dependencies: + '@babel/parser': 7.27.0 + '@vue/compiler-core': 3.5.13 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.5.3 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.13': + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/devtools-api@6.6.4': {} + + '@vue/eslint-config-prettier@7.1.0(eslint@9.25.1)(prettier@2.8.8)': + dependencies: + eslint: 9.25.1 + eslint-config-prettier: 8.10.0(eslint@9.25.1) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.10.0(eslint@9.25.1))(eslint@9.25.1)(prettier@2.8.8) + prettier: 2.8.8 + + '@vue/reactivity@3.5.13': + dependencies: + '@vue/shared': 3.5.13 + + '@vue/runtime-core@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/runtime-dom@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/runtime-core': 3.5.13 + '@vue/shared': 3.5.13 + csstype: 3.1.3 + + '@vue/server-renderer@3.5.13(vue@3.5.13)': + dependencies: + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + vue: 3.5.13 + + '@vue/shared@3.5.13': {} + + '@vueuse/core@10.11.1(vue@3.5.13)': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1(vue@3.5.13) + vue-demi: 0.14.10(vue@3.5.13) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/metadata@10.11.1': {} + + '@vueuse/shared@10.11.1(vue@3.5.13)': + dependencies: + vue-demi: 0.14.10(vue@3.5.13) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + acorn-jsx@5.3.2(acorn@8.14.1): + dependencies: + acorn: 8.14.1 + + acorn@8.14.1: {} + + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-keywords@5.1.0(ajv@8.17.1): + dependencies: + ajv: 8.17.1 + fast-deep-equal: 3.1.3 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ant-design-vue@4.2.6(vue@3.5.13): + dependencies: + '@ant-design/colors': 6.0.0 + '@ant-design/icons-vue': 7.0.1(vue@3.5.13) + '@babel/runtime': 7.27.0 + '@ctrl/tinycolor': 3.6.1 + '@emotion/hash': 0.9.2 + '@emotion/unitless': 0.8.1 + '@simonwep/pickr': 1.8.2 + array-tree-filter: 2.1.0 + async-validator: 4.2.5 + csstype: 3.1.3 + dayjs: 1.11.13 + dom-align: 1.12.4 + dom-scroll-into-view: 2.0.1 + lodash: 4.17.21 + lodash-es: 4.17.21 + resize-observer-polyfill: 1.5.1 + scroll-into-view-if-needed: 2.2.31 + shallow-equal: 1.2.1 + stylis: 4.3.6 + throttle-debounce: 5.0.2 + vue: 3.5.13 + vue-types: 3.0.2(vue@3.5.13) + warning: 4.0.3 + + ant-design-x-vue@1.1.1(ant-design-vue@4.2.6(vue@3.5.13))(vue@3.5.13): + dependencies: + '@ant-design/fast-color': 2.0.6 + '@emotion/hash': 0.9.2 + '@emotion/unitless': 0.10.0 + ant-design-vue: 4.2.6(vue@3.5.13) + classnames: 2.5.1 + csstype: 3.1.3 + stylis: 4.3.6 + vue: 3.5.13 + + argparse@2.0.1: {} + + array-tree-filter@2.1.0: {} + + async-validator@4.2.5: {} + + asynckit@0.4.0: {} + + axios@1.9.0: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.2 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + big.js@5.2.2: {} + + boolbase@1.0.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + browserslist@4.24.4: + dependencies: + caniuse-lite: 1.0.30001715 + electron-to-chromium: 1.5.143 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.24.4) + + bubblesets-js@2.3.4: {} + + buffer-from@1.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001715: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chrome-trace-event@1.0.4: {} + + classnames@2.5.1: {} + + claygl@1.3.0: {} + + codemirror@6.0.1: + dependencies: + '@codemirror/autocomplete': 6.18.6 + '@codemirror/commands': 6.8.1 + '@codemirror/language': 6.11.0 + '@codemirror/lint': 6.8.5 + '@codemirror/search': 6.5.10 + '@codemirror/state': 6.5.2 + '@codemirror/view': 6.36.6 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comlink@4.4.2: {} + + commander@2.20.3: {} + + commander@7.2.0: {} + + compute-scroll-into-view@1.0.20: {} + + concat-map@0.0.1: {} + + copy-anything@2.0.6: + dependencies: + is-what: 3.14.1 + + copy-to-clipboard@3.3.3: + dependencies: + toggle-selection: 1.0.6 + + core-js@3.41.0: {} + + crelt@1.0.6: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + cssfilter@0.0.10: {} + + csstype@3.1.3: {} + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-binarytree@1.0.2: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force-3d@3.0.6: + dependencies: + d3-binarytree: 1.0.2 + d3-dispatch: 3.0.1 + d3-octree: 1.1.0 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo-projection@4.0.0: + dependencies: + commander: 7.2.0 + d3-array: 3.2.4 + d3-geo: 3.1.1 + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-octree@1.1.0: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-regression@1.3.10: {} + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre@0.8.5: + dependencies: + graphlib: 2.1.8 + lodash: 4.17.21 + + dayjs@1.11.13: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + delayed-stream@1.0.0: {} + + dom-align@1.12.4: {} + + dom-scroll-into-view@2.0.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + echarts-gl@2.0.9(echarts@5.6.0): + dependencies: + claygl: 1.3.0 + echarts: 5.6.0 + zrender: 5.6.1 + + echarts@5.6.0: + dependencies: + tslib: 2.3.0 + zrender: 5.6.1 + + electron-to-chromium@1.5.143: {} + + emojis-list@3.0.0: {} + + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + entities@4.5.0: {} + + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@8.10.0(eslint@9.25.1): + dependencies: + eslint: 9.25.1 + + eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@9.25.1))(eslint@9.25.1)(prettier@2.8.8): + dependencies: + eslint: 9.25.1 + prettier: 2.8.8 + prettier-linter-helpers: 1.0.0 + optionalDependencies: + eslint-config-prettier: 8.10.0(eslint@9.25.1) + + eslint-plugin-vue@9.33.0(eslint@9.25.1): + dependencies: + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1) + eslint: 9.25.1 + globals: 13.24.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.1.2 + semver: 7.7.1 + vue-eslint-parser: 9.4.3(eslint@9.25.1) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-scope@8.3.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.25.1: + dependencies: + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.20.0 + '@eslint/config-helpers': 0.2.1 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.25.1 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) + eslint-visitor-keys: 4.2.0 + + espree@9.6.1: + dependencies: + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) + eslint-visitor-keys: 3.4.3 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + eventemitter3@5.0.1: {} + + events@3.3.0: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.6: {} + + fecha@4.2.3: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + follow-redirects@1.15.9: {} + + form-data@4.0.2: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + gl-matrix@3.4.3: {} + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-to-regexp@0.4.1: {} + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globals@14.0.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphlib@2.1.8: + dependencies: + lodash: 4.17.21 + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + highlight.js@11.11.1: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + image-size@0.5.5: + optional: true + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + internmap@2.0.3: {} + + is-any-array@2.0.1: {} + + is-arrayish@0.3.2: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-plain-object@3.0.1: {} + + is-what@3.14.1: {} + + isexe@2.0.0: {} + + jest-worker@27.5.1: + dependencies: + '@types/node': 22.15.3 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + less@4.3.0: + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.8.1 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.3.1 + source-map: 0.6.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + loader-runner@4.3.0: {} + + loader-utils@2.0.4: + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 2.2.3 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash-es@4.17.21: {} + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@10.4.3: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + optional: true + + markdown-it-image-figures@2.1.1(markdown-it@14.1.0): + dependencies: + markdown-it: 14.1.0 + + markdown-it-sub@2.0.0: {} + + markdown-it-sup@2.0.0: {} + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + marked-highlight@2.2.1(marked@13.0.3): + dependencies: + marked: 13.0.3 + + marked@13.0.3: {} + + math-intrinsics@1.1.0: {} + + md-editor-v3@4.21.3(vue@3.5.13): + dependencies: + '@codemirror/lang-markdown': 6.3.2 + '@codemirror/language-data': 6.5.1 + '@types/markdown-it': 14.1.2 + '@vavt/util': 2.1.0 + codemirror: 6.0.1 + copy-to-clipboard: 3.3.3 + lru-cache: 10.4.3 + markdown-it: 14.1.0 + markdown-it-image-figures: 2.1.1(markdown-it@14.1.0) + markdown-it-sub: 2.0.0 + markdown-it-sup: 2.0.0 + medium-zoom: 1.1.0 + vue: 3.5.13 + xss: 1.0.15 + + mdurl@2.0.0: {} + + medium-zoom@1.1.0: {} + + merge-stream@2.0.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: + optional: true + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + ml-array-max@1.2.4: + dependencies: + is-any-array: 2.0.1 + + ml-array-min@1.2.3: + dependencies: + is-any-array: 2.0.1 + + ml-array-rescale@1.3.7: + dependencies: + is-any-array: 2.0.1 + ml-array-max: 1.2.4 + ml-array-min: 1.2.3 + + ml-matrix@6.12.1: + dependencies: + is-any-array: 2.0.1 + ml-array-rescale: 1.3.7 + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + nanopop@2.4.2: {} + + natural-compare@1.4.0: {} + + needle@3.3.1: + dependencies: + iconv-lite: 0.6.3 + sax: 1.4.1 + optional: true + + neo-async@2.6.2: {} + + node-releases@2.0.19: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-node-version@1.0.1: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + pify@4.0.1: + optional: true + + pinia@2.3.1(vue@3.5.13): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.13 + vue-demi: 0.14.10(vue@3.5.13) + transitivePeerDependencies: + - '@vue/composition-api' + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.3: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@2.8.8: {} + + proxy-from-env@1.1.0: {} + + prr@1.0.1: + optional: true + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + quickselect@2.0.0: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + rbush@3.0.1: + dependencies: + quickselect: 2.0.0 + + regenerator-runtime@0.14.1: {} + + require-from-string@2.0.2: {} + + resize-observer-polyfill@1.5.1: {} + + resolve-from@4.0.0: {} + + robust-predicates@3.0.2: {} + + rollup@3.29.5: + optionalDependencies: + fsevents: 2.3.3 + + rw@1.3.3: {} + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + sax@1.4.1: + optional: true + + schema-utils@4.3.2: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.17.1) + + scroll-into-view-if-needed@2.2.31: + dependencies: + compute-scroll-into-view: 1.0.20 + + semver@5.7.2: + optional: true + + semver@7.7.1: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + shallow-equal@1.2.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + strip-json-comments@3.1.1: {} + + style-mod@4.1.2: {} + + stylis@4.3.6: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + svg-path-parser@1.1.0: {} + + tapable@2.2.1: {} + + terser-webpack-plugin@5.3.14(webpack@5.99.7): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 4.3.2 + serialize-javascript: 6.0.2 + terser: 5.39.0 + webpack: 5.99.7 + + terser@5.39.0: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.1 + commander: 2.20.3 + source-map-support: 0.5.21 + + throttle-debounce@5.0.2: {} + + toggle-selection@1.0.6: {} + + tslib@2.3.0: {} + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + uc.micro@2.1.0: {} + + undici-types@6.21.0: {} + + update-browserslist-db@1.1.3(browserslist@4.24.4): + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + vite@4.5.13(@types/node@22.15.3)(less@4.3.0)(terser@5.39.0): + dependencies: + esbuild: 0.18.20 + postcss: 8.5.3 + rollup: 3.29.5 + optionalDependencies: + '@types/node': 22.15.3 + fsevents: 2.3.3 + less: 4.3.0 + terser: 5.39.0 + + vue-demi@0.14.10(vue@3.5.13): + dependencies: + vue: 3.5.13 + + vue-eslint-parser@9.4.3(eslint@9.25.1): + dependencies: + debug: 4.4.0 + eslint: 9.25.1 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + lodash: 4.17.21 + semver: 7.7.1 + transitivePeerDependencies: + - supports-color + + vue-router@4.5.1(vue@3.5.13): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.13 + + vue-types@3.0.2(vue@3.5.13): + dependencies: + is-plain-object: 3.0.1 + vue: 3.5.13 + + vue@3.5.13: + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-sfc': 3.5.13 + '@vue/runtime-dom': 3.5.13 + '@vue/server-renderer': 3.5.13(vue@3.5.13) + '@vue/shared': 3.5.13 + + w3c-keyname@2.2.8: {} + + warning@4.0.3: + dependencies: + loose-envify: 1.4.0 + + watchpack@2.4.2: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + webpack-sources@3.2.3: {} + + webpack@5.99.7: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.14.1 + browserslist: 4.24.4 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.1 + es-module-lexer: 1.7.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.2 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.14(webpack@5.99.7) + watchpack: 2.4.2 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + workerize-loader@2.0.2(webpack@5.99.7): + dependencies: + loader-utils: 2.0.4 + webpack: 5.99.7 + + xml-name-validator@4.0.0: {} + + xss@1.0.15: + dependencies: + commander: 2.20.3 + cssfilter: 0.0.10 + + yocto-queue@0.1.0: {} + + zrender@5.6.1: + dependencies: + tslib: 2.3.0 From 8030aa9554e870c4174c9487a09559bd60730715 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Mon, 28 Apr 2025 23:48:01 +0800 Subject: [PATCH 04/74] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=96=B9=E6=B3=95=EF=BC=8C=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E9=80=9F=E5=BA=A6=E6=9B=B4=E5=BF=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 98 +++++----------------------- docker-compose.yml | 14 ++-- docker/api.Dockerfile | 11 ++-- docker/docker-compose.yml | 131 -------------------------------------- 4 files changed, 29 insertions(+), 225 deletions(-) delete mode 100644 docker/docker-compose.yml diff --git a/README.md b/README.md index 2497f6cf0..694cf454b 100644 --- a/README.md +++ b/README.md @@ -27,17 +27,13 @@ ## 📋 更新日志 +- **2025.04.27** - 支持 Ollama 等带有 `Content` 标签的消息解析 - **2025.03.30** - 系统中集成智能体(WIP, [PR#96](https://github.com/xerrors/Yuxi-Know/pull/96)) - **2025.02.24** - 新增网页检索以及内容展示,需配置 `TAVILY_API_KEY`,感谢 [littlewwwhite](https://github.com/littlewwwhite) - **2025.02.23** - SiliconFlow 的 Rerank 和 Embedding model 支持,现默认使用 SiliconFlow - **2025.02.20** - DeepSeek-R1 支持,需配置 `DEEPSEEK_API_KEY` 或 `SILICONFLOW_API_KEY` - **2024.10.12** - 后端修改为 [FastAPI](https://github.com/fastapi),添加 [Milvus-Standalone](https://github.com/milvus-io) 独立部署 -![功能展示](https://github.com/user-attachments/assets/8416a933-cc43-45d0-bf06-00df0ba6c4fb) - -| PC 网页 | 小屏设备 | -| :-------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | -| ![image](https://github.com/user-attachments/assets/5f3d7e69-baa8-4c59-90fc-391343e59af6) | ![image](https://github.com/user-attachments/assets/51efabce-a097-47fd-9fca-d3b0943af86a) | ### 环境配置 @@ -61,12 +57,11 @@ ZHIPUAI_API_KEY= # 如果配置 智谱清言 添加此行,并替换 **开发环境启动**(源代码修改会自动更新): ```bash -docker compose -f docker/docker-compose.dev.yml --env-file src/.env up --build +docker compose --env-file src/.env up --build ``` > 添加 `-d` 参数可在后台运行 - 成功启动后,会看到以下容器: ``` @@ -84,51 +79,14 @@ docker compose -f docker/docker-compose.dev.yml --env-file src/.env up --build ### 系统预览 -![系统演示](./images/demo.gif) - -问答支持 Deepseek-R1 等推理模型、知识图谱检索、知识库检索、网页检索 - -![Image](https://github.com/user-attachments/assets/97ad6771-e4a2-4324-a001-ecb0abe40fdd) - -网页检索结果: - -![Image](https://github.com/user-attachments/assets/20d51700-78d5-48a8-ab16-00bc98a1df37) - -知识图谱检索结果: - -![Image](https://github.com/user-attachments/assets/61b4e06f-4e6e-4a75-bfcb-b1a424523bb6) - -知识库检索结果 - -![Image](https://github.com/user-attachments/assets/53e786f4-08d7-45c1-bcec-df46d0c3c49b) - -知识库管理: - - -![Image](https://github.com/user-attachments/assets/55a6de55-59a0-4636-9c00-e4bfd6573c1b) - -![Image](https://github.com/user-attachments/assets/0f4f39ba-e6b7-4f18-a3c3-147477922f58) - - -知识图谱 - -![Image](https://github.com/user-attachments/assets/5849d875-801c-4d29-9d38-9245685e9d73) - -可视化配置: - -![Image](https://github.com/user-attachments/assets/5faac8bc-7968-42d0-a77d-5f8881a24de1) - -丰富的模型支持: - -![Image](https://github.com/user-attachments/assets/7a54ca07-78da-4aef-b0a0-47aa539dae8e) - +> 待补充 ### 服务管理 **关闭服务**: ```bash -docker compose -f docker/docker-compose.dev.yml --env-file src/.env down +docker compose --env-file src/.env down ``` **查看日志**: @@ -143,14 +101,14 @@ docker logs <容器名称> # 例如:docker logs api-dev 本项目支持通过 API 调用的模型,本地模型需使用 vllm、ollama 转成 API 服务后使用。 -| 模型供应商 | 默认模型 | 配置项目 | -| :--------------------- | :---------------------------------- | :--------------------------------------------- | -| `siliconflow` (默认) | `Qwen/Qwen2.5-7B-Instruct` (免费) | `SILICONFLOW_API_KEY` | -| `openai` | `gpt-4o` | `OPENAI_API_KEY` | -| `deepseek` | `deepseek-chat` | `DEEPSEEK_API_KEY` | -| `arc`(豆包方舟) | `doubao-1-5-pro-32k-250115` | `ARK_API_KEY` | -| `zhipu`(智谱清言) | `glm-4-flash` | `ZHIPUAI_API_KEY` | -| `dashscope`(阿里) | `qwen-max-latest` | `DASHSCOPE_API_KEY` | +| 模型供应商 | 默认模型 | 配置项目 | +| :--------------------- | :---------------------------------- | :---------------------- | +| `siliconflow` (默认) | `Qwen/Qwen2.5-7B-Instruct` (免费) | `SILICONFLOW_API_KEY` | +| `openai` | `gpt-4o` | `OPENAI_API_KEY` | +| `deepseek` | `deepseek-chat` | `DEEPSEEK_API_KEY` | +| `arc`(豆包方舟) | `doubao-1-5-pro-32k-250115` | `ARK_API_KEY` | +| `zhipu`(智谱清言) | `glm-4-flash` | `ZHIPUAI_API_KEY` | +| `dashscope`(阿里) | `qwen-max-latest` | `DASHSCOPE_API_KEY` | #### 添加新模型供应商 @@ -189,7 +147,6 @@ ark: ![image](https://github.com/user-attachments/assets/ab62ea17-c7d0-4f94-84af-c4bab26865ad) - **添加向量模型** ```yaml @@ -215,20 +172,9 @@ ark: ## 📚 知识库支持 -本项目支持多种格式的知识库文件: - -- PDF -- Txt -- Markdown -- Docx - -文件上传后,系统会: +本项目支持多种格式的知识库文件:PDF、TXT、Markdown、Docx。 -1. 将文件转换为纯文本 -2. 使用向量模型将文本转换为向量 -3. 存储到向量数据库中 - -> 此过程可能需要一定时间,请耐心等待。 +文件上传后,系统会 对文件进行分块、索引、存储到向量数据库(Milvus)中,此过程可能需要一定时间,请耐心等待。 ## 🕸️ 知识图谱支持 @@ -249,7 +195,7 @@ ark: - 默认账户:`neo4j` - 默认密码:`0123456789` -可在 `docker/docker-compose.yml` 和 `docker/docker-compose.dev.yml` 中修改配置(注意同时修改 `api.environment` 和 `graph.environment`)。 +可在 `docker-compose.yml` 中修改配置(注意同时修改 `api.environment` 和 `graph.environment`)。 目前项目暂不支持同时查询多个知识图谱。如已有基于 neo4j 的知识图谱,可删除 `docker-compose.yml` 中的 `graph` 配置项,并修改 `api.environment` 中的 `NEO4J_URI` 为您的 neo4j 服务地址。同时,需要确保节点的标签中包含 Entity 标签,才能正常触发索引。 @@ -261,20 +207,6 @@ ark: 贡献者名单 -## ❓ 常见问题 - -### 镜像下载问题 - -如无法直接下载相关镜像,可参考 [DaoCloud/public-image-mirror](https://github.com/DaoCloud/public-image-mirror?tab=readme-ov-file#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B),尝试替换前缀: - -```bash -# 以 neo4j 为例,其余类似 -docker pull m.daocloud.io/docker.io/library/neo4j:latest - -# 然后重命名镜像 -docker tag m.daocloud.io/docker.io/library/neo4j:latest neo4j:latest -``` - ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=xerrors/Yuxi-Know)](https://star-history.com/#xerrors/Yuxi-Know) diff --git a/docker-compose.yml b/docker-compose.yml index 9b620cd4b..c81e0c2cb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,7 @@ services: - MILVUS_URI=http://milvus:19530 - MODEL_DIR=/models # 优先级高于 .env 中的 MODEL_DIR - RUNNING_IN_DOCKER=true - command: uvicorn server.main:app --host 0.0.0.0 --port 5050 --reload + command: uv run uvicorn server.main:app --host 0.0.0.0 --port 5050 --reload web: build: @@ -52,8 +52,8 @@ services: - "7474:7474" - "7687:7687" volumes: - - ./volumes/neo4j/data:/data - - ./volumes/neo4j/logs:/var/lib/neo4j/logs + - ./docker/volumes/neo4j/data:/data + - ./docker/volumes/neo4j/logs:/var/lib/neo4j/logs environment: - NEO4J_AUTH=neo4j/0123456789 - NEO4J_server_bolt_listen__address=0.0.0.0:7687 @@ -71,7 +71,7 @@ services: - ETCD_QUOTA_BACKEND_BYTES=4294967296 - ETCD_SNAPSHOT_COUNT=50000 volumes: - - ./volumes/milvus/etcd:/etcd + - ./docker/volumes/milvus/etcd:/etcd command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd healthcheck: test: ["CMD", "etcdctl", "endpoint", "health"] @@ -88,7 +88,7 @@ services: MINIO_ACCESS_KEY: minioadmin MINIO_SECRET_KEY: minioadmin volumes: - - ./volumes/milvus/minio:/minio_data + - ./docker/volumes/milvus/minio:/minio_data command: minio server /minio_data healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] @@ -109,8 +109,8 @@ services: MINIO_ADDRESS: minio:9000 MILVUS_LOG_LEVEL: error # Add this line to reduce log output volumes: - - ./volumes/milvus/milvus:/var/lib/milvus - - ./volumes/milvus/logs:/var/lib/milvus/logs + - ./docker/volumes/milvus/milvus:/var/lib/milvus + - ./docker/volumes/milvus/logs:/var/lib/milvus/logs healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] interval: 30s diff --git a/docker/api.Dockerfile b/docker/api.Dockerfile index 080582c83..571a5f815 100644 --- a/docker/api.Dockerfile +++ b/docker/api.Dockerfile @@ -4,19 +4,22 @@ FROM python:3.12 # 设置工作目录 WORKDIR /app +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + python3-dev \ + ffmpeg \ + libsm6 \ + libxext6 + # 复制 requirements.txt 文件(这一步如果文件没变,Docker 会使用缓存) # COPY../requirements.txt /app/requirements.txt COPY ../pyproject.toml /app/pyproject.toml -COPY ../uv.lock /app/uv.lock COPY ../.python-version /app/.python-version # 安装依赖(Docker 会缓存这一步,除非 requirements.txt 发生变化) RUN pip install uv RUN uv sync -RUN apt-get clean -RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y - # 复制代码到容器中 COPY ../src /app/src COPY ../server /app/server diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml deleted file mode 100644 index a9b5a0c50..000000000 --- a/docker/docker-compose.yml +++ /dev/null @@ -1,131 +0,0 @@ -services: - api: - build: - context: .. - dockerfile: docker/api.Dockerfile - container_name: api-dev - working_dir: /app - volumes: - - ../server:/app/server - - ../src:/app/src - - ../saves_dev:/app/saves - # - ${MODEL_DIR}:/models # 如果出现 undefined volume MODEL_DIR: invalid compose project,请添加此环境变量或者注释此行 - ports: - - "5050:5050" - networks: - - app-network - extra_hosts: - - "host.docker.internal:host-gateway" - environment: - - NEO4J_URI=bolt://graph:7687 - - NEO4J_USERNAME=neo4j - - NEO4J_PASSWORD=0123456789 - - MILVUS_URI=http://milvus:19530 - - MODEL_DIR=/models # 优先级高于 .env 中的 MODEL_DIR - - RUNNING_IN_DOCKER=true - command: uvicorn server.main:app --host 0.0.0.0 --port 5050 --reload - - web: - build: - context: .. - dockerfile: docker/web.Dockerfile - target: development - container_name: web-dev - volumes: - - ../web:/app - - /app/node_modules - ports: - - "5173:5173" - depends_on: - - api - networks: - - app-network - environment: - - NODE_ENV=development - - VITE_API_URL=http://api:5050 # 添加这行 - command: pnpm run server - - graph: - image: neo4j:5.26 - container_name: graph-dev - ports: - - "7474:7474" - - "7687:7687" - volumes: - - ./volumes/neo4j/data:/data - - ./volumes/neo4j/logs:/var/lib/neo4j/logs - environment: - - NEO4J_AUTH=neo4j/0123456789 - - NEO4J_server_bolt_listen__address=0.0.0.0:7687 - - NEO4J_server_http_listen__address=0.0.0.0:7474 - - ENTITY_EMBEDDING=true - networks: - - app-network - - etcd: - container_name: milvus-etcd-dev - image: quay.io/coreos/etcd:v3.5.5 - environment: - - ETCD_AUTO_COMPACTION_MODE=revision - - ETCD_AUTO_COMPACTION_RETENTION=1000 - - ETCD_QUOTA_BACKEND_BYTES=4294967296 - - ETCD_SNAPSHOT_COUNT=50000 - volumes: - - ./volumes/milvus/etcd:/etcd - command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd - healthcheck: - test: ["CMD", "etcdctl", "endpoint", "health"] - interval: 30s - timeout: 20s - retries: 3 - networks: - - app-network - - minio: - container_name: milvus-minio-dev - image: minio/minio:RELEASE.2023-03-20T20-16-18Z - environment: - MINIO_ACCESS_KEY: minioadmin - MINIO_SECRET_KEY: minioadmin - volumes: - - ./volumes/milvus/minio:/minio_data - command: minio server /minio_data - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] - interval: 30s - timeout: 20s - retries: 3 - networks: - - app-network - - milvus: - image: milvusdb/milvus:v2.5.6 - container_name: milvus-standalone-dev - command: ["milvus", "run", "standalone"] - security_opt: - - seccomp:unconfined - environment: - ETCD_ENDPOINTS: etcd:2379 - MINIO_ADDRESS: minio:9000 - MILVUS_LOG_LEVEL: error # Add this line to reduce log output - volumes: - - ./volumes/milvus/milvus:/var/lib/milvus - - ./volumes/milvus/logs:/var/lib/milvus/logs - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] - interval: 30s - start_period: 90s - timeout: 20s - retries: 3 - ports: - - "19530:19530" - - "9091:9091" - depends_on: - - "etcd" - - "minio" - networks: - - app-network - -networks: - app-network: - driver: bridge From edb92517395b27900adf261a64bc6e54c361b2ad Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Tue, 29 Apr 2025 00:04:40 +0800 Subject: [PATCH 05/74] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 30 +++++++++++++++++++++++++++--- docker-compose.yml | 2 +- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 694cf454b..cf3984469 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ - **2025.02.20** - DeepSeek-R1 支持,需配置 `DEEPSEEK_API_KEY` 或 `SILICONFLOW_API_KEY` - **2024.10.12** - 后端修改为 [FastAPI](https://github.com/fastapi),添加 [Milvus-Standalone](https://github.com/milvus-io) 独立部署 - ### 环境配置 在启动前,您需要提供 API 服务商的 API_KEY,并放置在 `src/.env` 文件中(此文件项目中没有,需要自行参考 [src/.env.template](src/.env.template) 创建)。更多可配置项,可参考 后面**对话模型**部分。 @@ -143,11 +142,36 @@ ark: 对于**向量模型**和**重排序模型**,选择 `local` 前缀的模型会自动下载。如遇下载问题,请参考 [HF-Mirror](https://hf-mirror.com/) 配置。 -要使用已下载的本地模型,可在 models.yaml 或者网页设置中映射。 +要使用已下载的本地模型: + +1. 在网页设置中添加映射: ![image](https://github.com/user-attachments/assets/ab62ea17-c7d0-4f94-84af-c4bab26865ad) -**添加向量模型** +2. 将文件夹映射到 docker 内部 + +```yml +# docker-compose.yml + +services: + api: + build: + context: . + dockerfile: docker/api.Dockerfile + container_name: api-dev + working_dir: /app + volumes: + - ./server:/app/server + - ./src:/app/src + - ./saves:/app/saves + - ${MODEL_DIR}:/models <== 比如修改为 /hdd/models:models + ports: + +``` + +#### 添加向量模型 + +注:添加本地向量模型由于在 docker 内外的路径差异很大,因此建议参考前面的路径映射之后,在这里添加。 ```yaml # src/static/models.yaml diff --git a/docker-compose.yml b/docker-compose.yml index c81e0c2cb..fbe4018e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: volumes: - ./server:/app/server - ./src:/app/src - - ./saves_dev:/app/saves + - ./saves:/app/saves # - ${MODEL_DIR}:/models # 如果出现 undefined volume MODEL_DIR: invalid compose project,请添加此环境变量或者注释此行 ports: - "5050:5050" From bc168d08a9c359e1d2132ba0253cb2a002165b11 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Fri, 2 May 2025 23:56:59 +0800 Subject: [PATCH 06/74] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=8A=9F=E8=83=BD=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 + requirements.txt | 3 +- server/db_manager.py | 10 + server/main.py | 102 +++++- server/models/user_model.py | 56 +++ server/routers/__init__.py | 4 +- server/routers/admin_router.py | 55 ++- server/routers/auth_router.py | 347 +++++++++++++++++++ server/routers/chat_router.py | 98 ++++-- server/routers/data_router.py | 36 +- server/utils/__init__.py | 1 + server/utils/auth_middleware.py | 120 +++++++ server/utils/auth_utils.py | 75 ++++ src/config/__init__.py | 2 + web/src/apis/admin_api.js | 314 +++++++++++++++++ web/src/apis/auth_api.js | 106 ++++++ web/src/apis/base.js | 142 ++++++++ web/src/apis/index.js | 33 ++ web/src/apis/public_api.js | 59 ++++ web/src/components/AgentChatComponent.vue | 29 +- web/src/components/ChatComponent.vue | 44 ++- web/src/components/TokenManagerComponent.vue | 54 +-- web/src/components/UserInfoComponent.vue | 139 ++++++++ web/src/layouts/AppLayout.vue | 13 +- web/src/router/index.js | 140 +++++--- web/src/stores/user.js | 232 +++++++++++++ web/src/views/AgentSingleView.vue | 210 +++++------ web/src/views/AgentView.vue | 159 ++++++--- web/src/views/DataBaseInfoView.vue | 81 ++--- web/src/views/DataBaseView.vue | 43 +-- web/src/views/GraphView.vue | 130 +++---- web/src/views/HomeView.vue | 44 ++- web/src/views/LoginView.vue | 303 ++++++++++++++++ web/src/views/SettingView.vue | 339 +++++++++++++++++- 34 files changed, 2994 insertions(+), 531 deletions(-) create mode 100644 server/models/user_model.py create mode 100644 server/routers/auth_router.py create mode 100644 server/utils/__init__.py create mode 100644 server/utils/auth_middleware.py create mode 100644 server/utils/auth_utils.py create mode 100644 web/src/apis/admin_api.js create mode 100644 web/src/apis/auth_api.js create mode 100644 web/src/apis/base.js create mode 100644 web/src/apis/index.js create mode 100644 web/src/apis/public_api.js create mode 100644 web/src/components/UserInfoComponent.vue create mode 100644 web/src/stores/user.js create mode 100644 web/src/views/LoginView.vue diff --git a/pyproject.toml b/pyproject.toml index 64cc709b1..7651724ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,9 +19,11 @@ dependencies = [ "openai>=1.76.0", "opencv-python-headless>=4.11.0.86", "paddleocr>=2.10.0", + "pyjwt>=2.8.0", "pymilvus>=2.5.8", "pymupdf>=1.25.5", "python-dotenv>=1.1.0", + "python-jose[cryptography]>=3.4.0", "python-multipart>=0.0.20", "pyyaml>=6.0.2", "qianfan>=0.4.12.3", diff --git a/requirements.txt b/requirements.txt index 790c4f8ab..e0a7a1374 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,4 +31,5 @@ langchain langsmith langgraph langchain-openai -langchain-community \ No newline at end of file +langchain-community +PyJWT>=2.10.1 \ No newline at end of file diff --git a/server/db_manager.py b/server/db_manager.py index 0a05bcb91..6b526f2c0 100644 --- a/server/db_manager.py +++ b/server/db_manager.py @@ -6,6 +6,7 @@ from sqlalchemy.ext.declarative import declarative_base from server.models.token_model import Base, AgentToken +from server.models.user_model import User, OperationLog class DBManager: """数据库管理器""" @@ -32,6 +33,15 @@ def create_tables(self): """创建数据库表""" Base.metadata.create_all(self.engine) + def check_first_run(self): + """检查是否首次运行""" + session = self.get_session() + try: + # 检查是否有任何用户存在 + return session.query(User).count() == 0 + finally: + session.close() + def get_session(self): """获取数据库会话""" return self.Session() diff --git a/server/main.py b/server/main.py index 93277ccf1..5f383fc6e 100644 --- a/server/main.py +++ b/server/main.py @@ -1,8 +1,13 @@ import uvicorn -from fastapi import FastAPI +from fastapi import FastAPI, Request, HTTPException, status, Depends from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse +from starlette.middleware.base import BaseHTTPMiddleware + from server.routers import router +from server.utils.auth_middleware import get_current_user, is_public_path, is_admin_path +from server.models.user_model import User from src.utils.logging_config import logger @@ -18,6 +23,101 @@ allow_headers=["*"], ) +# 鉴权中间件 +class AuthMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next): + # 获取请求路径 + path = request.url.path + + # 检查是否为公开路径,公开路径无需身份验证 + if is_public_path(path): + return await call_next(request) + + # 注意:前端代理已经去掉了 /api 前缀,例如 /api/chat 变成了 /chat + # 判断是否需要验证的API请求,包括聊天、数据、工具等 + is_api_path = ( + path.startswith("/chat") or + path.startswith("/data") or + path.startswith("/admin") or + path.startswith("/auth") and not is_public_path(path) + ) + + if not is_api_path: + # 非API路径,可能是前端路由或静态资源 + return await call_next(request) + + # 提取Authorization头 + auth_header = request.headers.get("Authorization") + if not auth_header or not auth_header.startswith("Bearer "): + return JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + content={"detail": "请先登录"}, + headers={"WWW-Authenticate": "Bearer"} + ) + + # 获取token + token = auth_header.split("Bearer ")[1] + + # 添加token到请求状态,后续路由可以直接使用 + request.state.token = token + + # 检查是否需要管理员权限 + if is_admin_path(path): + # 尝试获取数据库会话 + try: + from server.db_manager import db_manager + from server.utils.auth_utils import AuthUtils + + db = db_manager.get_session() + try: + # 验证token并获取用户信息 + payload = AuthUtils.verify_access_token(token) + user_id = payload.get("sub") + + if not user_id: + return JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + content={"detail": "无效的用户标识"}, + headers={"WWW-Authenticate": "Bearer"} + ) + + # 查询用户信息 + from server.models.user_model import User + user = db.query(User).filter(User.id == user_id).first() + + if not user: + return JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + content={"detail": "用户不存在"}, + headers={"WWW-Authenticate": "Bearer"} + ) + + # 检查管理员权限 + if user.role not in ["admin", "superadmin"]: + return JSONResponse( + status_code=status.HTTP_403_FORBIDDEN, + content={"detail": "需要管理员权限"} + ) + + # 将用户信息添加到请求状态 + request.state.user = user + + finally: + db.close() + + except Exception as e: + logger.error(f"验证管理员权限出错: {e}") + return JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + content={"detail": "验证用户权限出错"}, + headers={"WWW-Authenticate": "Bearer"} + ) + + # 继续处理请求 + return await call_next(request) + +# 添加鉴权中间件 +app.add_middleware(AuthMiddleware) if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=5050, threads=10, workers=10, reload=True) diff --git a/server/models/user_model.py b/server/models/user_model.py new file mode 100644 index 000000000..fa0f4dfbe --- /dev/null +++ b/server/models/user_model.py @@ -0,0 +1,56 @@ +from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Text +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.sql import func +from sqlalchemy.orm import relationship + +from server.models.token_model import Base + +class User(Base): + """用户模型""" + __tablename__ = 'users' + + id = Column(Integer, primary_key=True, autoincrement=True) + username = Column(String, nullable=False, unique=True, index=True) + password_hash = Column(String, nullable=False) + role = Column(String, nullable=False, default='user') # 角色: superadmin, admin, user + created_at = Column(DateTime, default=func.now()) + last_login = Column(DateTime, nullable=True) + + # 关联操作日志 + operation_logs = relationship("OperationLog", back_populates="user") + + def to_dict(self, include_password=False): + result = { + "id": self.id, + "username": self.username, + "role": self.role, + "created_at": self.created_at.isoformat() if self.created_at else None, + "last_login": self.last_login.isoformat() if self.last_login else None + } + if include_password: + result["password_hash"] = self.password_hash + return result + +class OperationLog(Base): + """操作日志模型""" + __tablename__ = 'operation_logs' + + id = Column(Integer, primary_key=True, autoincrement=True) + user_id = Column(Integer, ForeignKey('users.id'), nullable=False) + operation = Column(String, nullable=False) + details = Column(Text, nullable=True) + ip_address = Column(String, nullable=True) + timestamp = Column(DateTime, default=func.now()) + + # 关联用户 + user = relationship("User", back_populates="operation_logs") + + def to_dict(self): + return { + "id": self.id, + "user_id": self.user_id, + "operation": self.operation, + "details": self.details, + "ip_address": self.ip_address, + "timestamp": self.timestamp.isoformat() if self.timestamp else None + } \ No newline at end of file diff --git a/server/routers/__init__.py b/server/routers/__init__.py index 6878d9347..b11f92745 100644 --- a/server/routers/__init__.py +++ b/server/routers/__init__.py @@ -2,12 +2,12 @@ from server.routers.chat_router import chat from server.routers.data_router import data from server.routers.base_router import base -from server.routers.tool_router import tool from server.routers.admin_router import admin +from server.routers.auth_router import auth router = APIRouter() router.include_router(base) router.include_router(chat) router.include_router(data) -router.include_router(tool) router.include_router(admin) +router.include_router(auth) diff --git a/server/routers/admin_router.py b/server/routers/admin_router.py index 9471b6bc3..1556e00eb 100644 --- a/server/routers/admin_router.py +++ b/server/routers/admin_router.py @@ -1,23 +1,18 @@ import secrets import string -from fastapi import APIRouter, Depends, HTTPException, Query +from fastapi import APIRouter, Depends, HTTPException, Query, Request from pydantic import BaseModel from typing import List, Optional from sqlalchemy.orm import Session from server.db_manager import db_manager from server.models.token_model import AgentToken +from server.models.user_model import User, OperationLog +from server.utils.auth_middleware import get_db, get_current_user, get_admin_user, oauth2_scheme +from server.routers.auth_router import log_operation admin = APIRouter(prefix="/admin", tags=["admin"]) -# 依赖项:获取数据库会话 -def get_db(): - db = db_manager.get_session() - try: - yield db - finally: - db.close() - # 请求和响应模型 class TokenCreate(BaseModel): agent_id: str @@ -42,9 +37,10 @@ def generate_token(length=32): @admin.get("/tokens", response_model=List[TokenResponse]) async def get_agent_tokens( agent_id: Optional[str] = Query(None), + current_user: User = Depends(get_admin_user), db: Session = Depends(get_db) ): - """获取智能体的token列表""" + """获取智能体的token列表(需要管理员权限)""" query = db.query(AgentToken) if agent_id: query = query.filter(AgentToken.agent_id == agent_id) @@ -54,9 +50,11 @@ async def get_agent_tokens( @admin.post("/tokens", response_model=TokenResponse) async def create_token( token_data: TokenCreate, + request: Request, + current_user: User = Depends(get_admin_user), db: Session = Depends(get_db) ): - """创建新的token""" + """创建新的token(需要管理员权限)""" # 生成随机token token_value = generate_token() @@ -72,15 +70,38 @@ async def create_token( db.commit() db.refresh(new_token) + # 记录操作 + log_operation( + db, + current_user.id, + "创建令牌", + f"为智能体 {token_data.agent_id} 创建访问令牌: {token_data.name}", + request + ) + return new_token.to_dict() @admin.delete("/tokens/{token_id}", response_model=dict) -async def delete_token(token_id: int, db: Session = Depends(get_db)): - """删除token""" +async def delete_token( + token_id: int, + request: Request, + current_user: User = Depends(get_admin_user), + db: Session = Depends(get_db) +): + """删除token(需要管理员权限)""" token = db.query(AgentToken).filter(AgentToken.id == token_id).first() if not token: raise HTTPException(status_code=404, detail="Token not found") + # 记录操作信息 + log_operation( + db, + current_user.id, + "删除令牌", + f"删除令牌ID: {token_id}, 智能体: {token.agent_id}, 名称: {token.name}", + request + ) + db.delete(token) db.commit() @@ -89,15 +110,17 @@ async def delete_token(token_id: int, db: Session = Depends(get_db)): @admin.post("/verify_token") async def verify_agent_token( token_data: TokenVerify, + token: Optional[str] = Depends(oauth2_scheme), db: Session = Depends(get_db) ): - """验证智能体访问令牌""" - token = db.query(AgentToken).filter( + """验证智能体访问令牌(所有用户都可访问)""" + # 查找令牌 + agent_token = db.query(AgentToken).filter( AgentToken.agent_id == token_data.agent_id, AgentToken.token == token_data.token ).first() - if not token: + if not agent_token: raise HTTPException(status_code=401, detail="Invalid token") return {"success": True, "message": "Token verified"} \ No newline at end of file diff --git a/server/routers/auth_router.py b/server/routers/auth_router.py new file mode 100644 index 000000000..08654bf81 --- /dev/null +++ b/server/routers/auth_router.py @@ -0,0 +1,347 @@ +from fastapi import APIRouter, Depends, HTTPException, Request, status +from fastapi.security import OAuth2PasswordRequestForm +from pydantic import BaseModel +from typing import List, Optional +from sqlalchemy.orm import Session +from datetime import datetime, timedelta + +from server.db_manager import db_manager +from server.models.user_model import User, OperationLog +from server.utils.auth_utils import AuthUtils +from server.utils.auth_middleware import get_db, get_current_user, get_admin_user, get_superadmin_user, oauth2_scheme + +# 创建路由器 +auth = APIRouter(prefix="/auth", tags=["auth"]) + +# 请求和响应模型 +class Token(BaseModel): + access_token: str + token_type: str + user_id: int + username: str + role: str + +class UserCreate(BaseModel): + username: str + password: str + role: str = "user" + +class UserUpdate(BaseModel): + username: Optional[str] = None + password: Optional[str] = None + role: Optional[str] = None + +class UserResponse(BaseModel): + id: int + username: str + role: str + created_at: str + last_login: Optional[str] = None + +class InitializeAdmin(BaseModel): + username: str + password: str + +# 记录操作日志 +def log_operation(db: Session, user_id: int, operation: str, details: str = None, request: Request = None): + ip_address = None + if request: + ip_address = request.client.host if request.client else None + + log = OperationLog( + user_id=user_id, + operation=operation, + details=details, + ip_address=ip_address + ) + db.add(log) + db.commit() + +# 路由:登录获取令牌 +@auth.post("/token", response_model=Token) +async def login_for_access_token( + form_data: OAuth2PasswordRequestForm = Depends(), + db: Session = Depends(get_db) +): + # 查找用户 + user = db.query(User).filter(User.username == form_data.username).first() + + # 验证用户存在且密码正确 + if not user or not AuthUtils.verify_password(user.password_hash, form_data.password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="用户名或密码错误", + headers={"WWW-Authenticate": "Bearer"}, + ) + + # 更新最后登录时间 + user.last_login = datetime.now() + db.commit() + + # 生成访问令牌 + token_data = {"sub": str(user.id)} + access_token = AuthUtils.create_access_token(token_data) + + # 记录登录操作 + log_operation(db, user.id, "登录") + + return { + "access_token": access_token, + "token_type": "bearer", + "user_id": user.id, + "username": user.username, + "role": user.role + } + +# 路由:校验是否需要初始化管理员 +@auth.get("/check-first-run") +async def check_first_run(): + is_first_run = db_manager.check_first_run() + return {"first_run": is_first_run} + +# 路由:初始化管理员账户 +@auth.post("/initialize", response_model=Token) +async def initialize_admin( + admin_data: InitializeAdmin, + db: Session = Depends(get_db) +): + # 检查是否是首次运行 + if not db_manager.check_first_run(): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="系统已经初始化,无法再次创建初始管理员", + ) + + # 创建管理员账户 + hashed_password = AuthUtils.hash_password(admin_data.password) + + new_admin = User( + username=admin_data.username, + password_hash=hashed_password, + role="superadmin", + last_login=datetime.now() + ) + + db.add(new_admin) + db.commit() + db.refresh(new_admin) + + # 生成访问令牌 + token_data = {"sub": str(new_admin.id)} + access_token = AuthUtils.create_access_token(token_data) + + # 记录操作 + log_operation(db, new_admin.id, "系统初始化", "创建超级管理员账户") + + return { + "access_token": access_token, + "token_type": "bearer", + "user_id": new_admin.id, + "username": new_admin.username, + "role": new_admin.role + } + +# 路由:获取当前用户信息 +@auth.get("/me", response_model=UserResponse) +async def read_users_me(current_user: User = Depends(get_current_user)): + return current_user.to_dict() + +# 路由:创建新用户(管理员权限) +@auth.post("/users", response_model=UserResponse) +async def create_user( + user_data: UserCreate, + request: Request, + current_user: User = Depends(get_admin_user), + db: Session = Depends(get_db) +): + # 检查用户名是否已存在 + existing_user = db.query(User).filter(User.username == user_data.username).first() + if existing_user: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="用户名已存在", + ) + + # 创建新用户 + hashed_password = AuthUtils.hash_password(user_data.password) + + # 检查角色权限 + # 超级管理员可以创建任何类型的用户 + if user_data.role == "superadmin" and current_user.role != "superadmin": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="只有超级管理员才能创建超级管理员账户", + ) + + # 管理员只能创建普通用户 + if current_user.role == "admin" and user_data.role != "user": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="管理员只能创建普通用户账户", + ) + + new_user = User( + username=user_data.username, + password_hash=hashed_password, + role=user_data.role + ) + + db.add(new_user) + db.commit() + db.refresh(new_user) + + # 记录操作 + log_operation( + db, + current_user.id, + "创建用户", + f"创建用户: {user_data.username}, 角色: {user_data.role}", + request + ) + + return new_user.to_dict() + +# 路由:获取所有用户(管理员权限) +@auth.get("/users", response_model=List[UserResponse]) +async def read_users( + skip: int = 0, + limit: int = 100, + current_user: User = Depends(get_admin_user), + db: Session = Depends(get_db) +): + users = db.query(User).offset(skip).limit(limit).all() + return [user.to_dict() for user in users] + +# 路由:获取特定用户信息(管理员权限) +@auth.get("/users/{user_id}", response_model=UserResponse) +async def read_user( + user_id: int, + current_user: User = Depends(get_admin_user), + db: Session = Depends(get_db) +): + user = db.query(User).filter(User.id == user_id).first() + if user is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在", + ) + return user.to_dict() + +# 路由:更新用户信息(管理员权限) +@auth.put("/users/{user_id}", response_model=UserResponse) +async def update_user( + user_id: int, + user_data: UserUpdate, + request: Request, + current_user: User = Depends(get_admin_user), + db: Session = Depends(get_db) +): + user = db.query(User).filter(User.id == user_id).first() + if user is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在", + ) + + # 检查权限 + if user.role == "superadmin" and current_user.role != "superadmin": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="只有超级管理员才能修改超级管理员账户", + ) + + # 超级管理员账户不能被降级(只能由其他超级管理员修改) + if user.role == "superadmin" and user_data.role and user_data.role != "superadmin" and current_user.id != user.id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="不能降级超级管理员账户", + ) + + # 更新信息 + update_details = [] + + if user_data.username is not None: + # 检查用户名是否已被其他用户使用 + existing_user = db.query(User).filter(User.username == user_data.username, User.id != user_id).first() + if existing_user: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="用户名已存在", + ) + user.username = user_data.username + update_details.append(f"用户名: {user_data.username}") + + if user_data.password is not None: + user.password_hash = AuthUtils.hash_password(user_data.password) + update_details.append("密码已更新") + + if user_data.role is not None: + user.role = user_data.role + update_details.append(f"角色: {user_data.role}") + + db.commit() + + # 记录操作 + log_operation( + db, + current_user.id, + "更新用户", + f"更新用户ID {user_id}: {', '.join(update_details)}", + request + ) + + return user.to_dict() + +# 路由:删除用户(管理员权限) +@auth.delete("/users/{user_id}", response_model=dict) +async def delete_user( + user_id: int, + request: Request, + current_user: User = Depends(get_admin_user), + db: Session = Depends(get_db) +): + user = db.query(User).filter(User.id == user_id).first() + if user is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="用户不存在", + ) + + # 检查权限 + if user.role == "superadmin": + # 只有超级管理员可以删除超级管理员 + if current_user.role != "superadmin": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="只有超级管理员才能删除超级管理员账户", + ) + + # 检查是否是最后一个超级管理员 + superadmin_count = db.query(User).filter(User.role == "superadmin").count() + if superadmin_count <= 1: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="不能删除最后一个超级管理员账户", + ) + + # 不能删除自己的账户 + if user.id == current_user.id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="不能删除自己的账户", + ) + + # 记录操作 + log_operation( + db, + current_user.id, + "删除用户", + f"删除用户: {user.username}, ID: {user.id}, 角色: {user.role}", + request + ) + + # 删除用户 + db.delete(user) + db.commit() + + return {"success": True, "message": "用户已删除"} \ No newline at end of file diff --git a/server/routers/chat_router.py b/server/routers/chat_router.py index 9c5fb82d3..8fe2fb23f 100644 --- a/server/routers/chat_router.py +++ b/server/routers/chat_router.py @@ -13,11 +13,54 @@ from src.models import select_model from src.utils.logging_config import logger from src.agents.tools_factory import get_all_tools +from server.routers.auth_router import get_admin_user +from server.utils.auth_middleware import get_required_user +from server.models.user_model import User chat = APIRouter(prefix="/chat") +@chat.get("/default_agent") +async def get_default_agent(current_user: User = Depends(get_required_user)): + """获取默认智能体ID(需要登录)""" + try: + default_agent_id = config.default_agent_id + # 如果没有设置默认智能体,尝试获取第一个可用的智能体 + if not default_agent_id: + agents = [agent.get_info() for agent in agent_manager.agents.values()] + if agents: + default_agent_id = agents[0].get("name", "") + + return {"default_agent_id": default_agent_id} + except Exception as e: + logger.error(f"获取默认智能体出错: {e}") + raise HTTPException(status_code=500, detail=f"获取默认智能体出错: {str(e)}") + +@chat.post("/set_default_agent") +async def set_default_agent(agent_id: str = Body(..., embed=True), current_user = Depends(get_admin_user)): + """设置默认智能体ID (仅管理员)""" + try: + # 验证智能体是否存在 + agents = [agent.get_info() for agent in agent_manager.agents.values()] + agent_ids = [agent.get("name", "") for agent in agents] + + if agent_id not in agent_ids: + raise HTTPException(status_code=404, detail=f"智能体 {agent_id} 不存在") + + # 设置默认智能体ID + config.default_agent_id = agent_id + # 保存配置 + config.save() + + return {"success": True, "default_agent_id": agent_id} + except HTTPException as he: + raise he + except Exception as e: + logger.error(f"设置默认智能体出错: {e}") + raise HTTPException(status_code=500, detail=f"设置默认智能体出错: {str(e)}") + @chat.get("/") -async def chat_get(): +async def chat_get(current_user: User = Depends(get_required_user)): + """聊天服务健康检查(需要登录)""" return "Chat Get!" @chat.post("/") @@ -25,29 +68,9 @@ async def chat_post( query: str = Body(...), meta: dict = Body(None), history: list[dict] | None = Body(None), - thread_id: str | None = Body(None)): - """处理聊天请求的主要端点。 - Args: - query: 用户的输入查询文本 - meta: 包含请求元数据的字典,可以包含以下字段: - - use_web: 是否使用网络搜索 - - use_graph: 是否使用知识图谱 - - db_id: 数据库ID - - history_round: 历史对话轮数限制 - - system_prompt: 系统提示词(str,不含变量) - history: 对话历史记录列表 - thread_id: 对话线程ID - Returns: - StreamingResponse: 返回一个流式响应,包含以下状态: - - searching: 正在搜索知识库 - - generating: 正在生成回答 - - reasoning: 正在推理 - - loading: 正在加载回答 - - finished: 回答完成 - - error: 发生错误 - Raises: - HTTPException: 当检索器或模型发生错误时抛出 - """ + thread_id: str | None = Body(None), + current_user: User = Depends(get_required_user)): + """处理聊天请求的主要端点(需要登录)""" model = select_model() meta["server_model_name"] = model.model_name @@ -117,7 +140,8 @@ def generate_response(): return StreamingResponse(generate_response(), media_type='application/json') @chat.post("/call") -async def call(query: str = Body(...), meta: dict = Body(None)): +async def call(query: str = Body(...), meta: dict = Body(None), current_user: User = Depends(get_required_user)): + """调用模型进行简单问答(需要登录)""" meta = meta or {} model = select_model(model_provider=meta.get("model_provider"), model_name=meta.get("model_name")) async def predict_async(query): @@ -130,7 +154,8 @@ async def predict_async(query): return {"response": response.content} @chat.post("/call_lite") -async def call_lite(query: str = Body(...), meta: dict = Body(None)): +async def call_lite(query: str = Body(...), meta: dict = Body(None), current_user: User = Depends(get_required_user)): + """使用轻量版模型进行问答(需要登录)""" meta = meta or {} async def predict_async(query): loop = asyncio.get_event_loop() @@ -145,7 +170,8 @@ async def predict_async(query): return {"response": response.content} @chat.get("/agent") -async def get_agent(): +async def get_agent(current_user: User = Depends(get_required_user)): + """获取所有可用智能体(需要登录)""" agents = [agent.get_info() for agent in agent_manager.agents.values()] return {"agents": agents} @@ -154,12 +180,14 @@ def chat_agent(agent_name: str, query: str = Body(...), history: list = Body(...), config: dict = Body({}), - meta: dict = Body({})): + meta: dict = Body({}), + current_user: User = Depends(get_required_user)): + """使用特定智能体进行对话(需要登录)""" meta.update({ "query": query, "agent_name": agent_name, - "server_model_name": config.get("model", agent_name) , + "server_model_name": config.get("model", agent_name), "thread_id": config.get("thread_id"), }) @@ -223,19 +251,19 @@ def stream_messages(): return StreamingResponse(stream_messages(), media_type='application/json') @chat.get("/models") -async def get_chat_models(model_provider: str): - """获取指定模型提供商的模型列表""" +async def get_chat_models(model_provider: str, current_user: User = Depends(get_admin_user)): + """获取指定模型提供商的模型列表(需要登录)""" model = select_model(model_provider=model_provider) return {"models": model.get_models()} @chat.post("/models/update") -async def update_chat_models(model_provider: str, model_names: list[str]): - """更新指定模型提供商的模型列表""" +async def update_chat_models(model_provider: str, model_names: list[str], current_user = Depends(get_admin_user)): + """更新指定模型提供商的模型列表 (仅管理员)""" config.model_names[model_provider]["models"] = model_names config._save_models_to_file() return {"models": config.model_names[model_provider]["models"]} @chat.get("/tools") -async def get_tools(): - """获取所有工具""" +async def get_tools(current_user: User = Depends(get_admin_user)): + """获取所有可用工具(需要登录)""" return {"tools": list(get_all_tools().keys())} diff --git a/server/routers/data_router.py b/server/routers/data_router.py index 699ed9681..3b5534080 100644 --- a/server/routers/data_router.py +++ b/server/routers/data_router.py @@ -6,12 +6,14 @@ from src.utils import logger, hashstr from src import executor, retriever, config, knowledge_base, graph_base +from server.utils.auth_middleware import get_admin_user +from server.models.user_model import User data = APIRouter(prefix="/data") @data.get("/") -async def get_databases(): +async def get_databases(current_user: User = Depends(get_admin_user)): try: database = knowledge_base.get_databases() except Exception as e: @@ -23,7 +25,8 @@ async def get_databases(): async def create_database( database_name: str = Body(...), description: str = Body(...), - dimension: Optional[int] = Body(None) + dimension: Optional[int] = Body(None), + current_user: User = Depends(get_admin_user) ): logger.debug(f"Create database {database_name}") try: @@ -38,25 +41,25 @@ async def create_database( return database_info @data.delete("/") -async def delete_database(db_id): +async def delete_database(db_id, current_user: User = Depends(get_admin_user)): logger.debug(f"Delete database {db_id}") knowledge_base.delete_database(db_id) return {"message": "删除成功"} @data.post("/query-test") -async def query_test(query: str = Body(...), meta: dict = Body(...)): +async def query_test(query: str = Body(...), meta: dict = Body(...), current_user: User = Depends(get_admin_user)): logger.debug(f"Query test in {meta}: {query}") result = retriever.query_knowledgebase(query, history=None, refs={"meta": meta}) return result @data.post("/file-to-chunk") -async def file_to_chunk(files: List[str] = Body(...), params: dict = Body(...)): +async def file_to_chunk(files: List[str] = Body(...), params: dict = Body(...), current_user: User = Depends(get_admin_user)): logger.debug(f"File to chunk: {files}") result = knowledge_base.file_to_chunk(files, params=params) return result @data.post("/add-by-file") -async def create_document_by_file(db_id: str = Body(...), files: List[str] = Body(...)): +async def create_document_by_file(db_id: str = Body(...), files: List[str] = Body(...), current_user: User = Depends(get_admin_user)): logger.debug(f"Add document in {db_id} by file: {files}") try: # 使用线程池执行耗时操作 @@ -71,7 +74,7 @@ async def create_document_by_file(db_id: str = Body(...), files: List[str] = Bod return {"message": f"添加文件失败: {e}", "status": "failed"} @data.post("/add-by-chunks") -async def add_by_chunks(db_id: str = Body(...), file_chunks: dict = Body(...)): +async def add_by_chunks(db_id: str = Body(...), file_chunks: dict = Body(...), current_user: User = Depends(get_admin_user)): # logger.debug(f"Add chunks in {db_id}: {len(file_chunks)} chunks") try: loop = asyncio.get_event_loop() @@ -85,7 +88,7 @@ async def add_by_chunks(db_id: str = Body(...), file_chunks: dict = Body(...)): return {"message": f"添加分块失败: {e}", "status": "failed"} @data.get("/info") -async def get_database_info(db_id: str): +async def get_database_info(db_id: str, current_user: User = Depends(get_admin_user)): # logger.debug(f"Get database {db_id} info") database = knowledge_base.get_database_info(db_id) if database is None: @@ -93,13 +96,13 @@ async def get_database_info(db_id: str): return database @data.delete("/document") -async def delete_document(db_id: str = Body(...), file_id: str = Body(...)): +async def delete_document(db_id: str = Body(...), file_id: str = Body(...), current_user: User = Depends(get_admin_user)): logger.debug(f"DELETE document {file_id} info in {db_id}") knowledge_base.delete_file(db_id, file_id) return {"message": "删除成功"} @data.get("/document") -async def get_document_info(db_id: str, file_id: str): +async def get_document_info(db_id: str, file_id: str, current_user: User = Depends(get_admin_user)): logger.debug(f"GET document {file_id} info in {db_id}") try: @@ -113,7 +116,8 @@ async def get_document_info(db_id: str, file_id: str): @data.post("/upload") async def upload_file( file: UploadFile = File(...), - db_id: Optional[str] = Query(None) + db_id: Optional[str] = Query(None), + current_user: User = Depends(get_admin_user) ): if not file.filename: raise HTTPException(status_code=400, detail="No selected file") @@ -135,14 +139,14 @@ async def upload_file( return {"message": "File successfully uploaded", "file_path": file_path, "db_id": db_id} @data.get("/graph") -async def get_graph_info(): +async def get_graph_info(current_user: User = Depends(get_admin_user)): graph_info = graph_base.get_graph_info() if graph_info is None: raise HTTPException(status_code=400, detail="图数据库获取出错") return graph_info @data.post("/graph/index-nodes") -async def index_nodes(data: dict = Body(default={})): +async def index_nodes(data: dict = Body(default={}), current_user: User = Depends(get_admin_user)): if not graph_base.is_running(): raise HTTPException(status_code=400, detail="图数据库未启动") @@ -155,12 +159,12 @@ async def index_nodes(data: dict = Body(default={})): return {"status": "success", "message": f"已成功为{count}个节点添加嵌入向量", "indexed_count": count} @data.get("/graph/node") -async def get_graph_node(entity_name: str): +async def get_graph_node(entity_name: str, current_user: User = Depends(get_admin_user)): result = graph_base.query_node(entity_name=entity_name) return {"result": graph_base.format_query_result_to_graph(result), "message": "success"} @data.get("/graph/nodes") -async def get_graph_nodes(kgdb_name: str, num: int): +async def get_graph_nodes(kgdb_name: str, num: int, current_user: User = Depends(get_admin_user)): if not config.enable_knowledge_graph: raise HTTPException(status_code=400, detail="Knowledge graph is not enabled") @@ -169,7 +173,7 @@ async def get_graph_nodes(kgdb_name: str, num: int): return {"result": graph_base.format_general_results(result), "message": "success"} @data.post("/graph/add-by-jsonl") -async def add_graph_entity(file_path: str = Body(...), kgdb_name: Optional[str] = Body(None)): +async def add_graph_entity(file_path: str = Body(...), kgdb_name: Optional[str] = Body(None), current_user: User = Depends(get_admin_user)): if not config.enable_knowledge_graph: return {"message": "知识图谱未启用", "status": "failed"} diff --git a/server/utils/__init__.py b/server/utils/__init__.py new file mode 100644 index 000000000..4901b7189 --- /dev/null +++ b/server/utils/__init__.py @@ -0,0 +1 @@ +# utils包初始化文件 \ No newline at end of file diff --git a/server/utils/auth_middleware.py b/server/utils/auth_middleware.py new file mode 100644 index 000000000..692f872fb --- /dev/null +++ b/server/utils/auth_middleware.py @@ -0,0 +1,120 @@ +from typing import Optional, List +from fastapi import Depends, HTTPException, status +from fastapi.security import OAuth2PasswordBearer +from sqlalchemy.orm import Session +from jose import JWTError, jwt +import re + +from server.db_manager import db_manager +from server.models.user_model import User +from server.utils.auth_utils import AuthUtils + +# 定义OAuth2密码承载器,指定token URL +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token", auto_error=False) + +# 公开路径列表,无需登录即可访问 +PUBLIC_PATHS = [ + r"^/auth/token$", # 登录 + r"^/auth/check-first-run$", # 检查是否首次运行 + r"^/auth/initialize$", # 初始化系统 + r"^/docs$", r"^/redoc$", r"^/openapi.json$", # API文档 + r"^/static/.*$", # 静态资源 + r"^/assets/.*$", # 前端资源文件 + r"^/$", # 根路径(登录页) + r"^/login$", # 登录页面 + r"^/home$", # 首页 + r"^/home/.*$", # 首页下的所有路径 + r"^/favicon\.ico$", # 网站图标 + r"^/_nuxt/.*$", # Nuxt.js生成的资源文件 + r"^/js/.*$", # JavaScript文件 + r"^/css/.*$", # CSS文件 + r"^/img/.*$" # 图片文件 +] + +# 获取数据库会话 +def get_db(): + db = db_manager.get_session() + try: + yield db + finally: + db.close() + +# 获取当前用户 +async def get_current_user(token: Optional[str] = Depends(oauth2_scheme), db: Session = Depends(get_db)): + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="无效的凭证", + headers={"WWW-Authenticate": "Bearer"}, + ) + + # 允许无token访问公开路径 + if token is None: + return None + + try: + # 验证token + payload = AuthUtils.verify_access_token(token) + user_id = payload.get("sub") + if user_id is None: + raise credentials_exception + except JWTError: + raise credentials_exception + + # 查找用户 + user = db.query(User).filter(User.id == user_id).first() + if user is None: + raise credentials_exception + + return user + +# 获取已登录用户(抛出401如果未登录) +async def get_required_user(user: Optional[User] = Depends(get_current_user)): + if user is None: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="请登录后再访问", + headers={"WWW-Authenticate": "Bearer"}, + ) + return user + +# 获取管理员用户 +async def get_admin_user(current_user: User = Depends(get_required_user)): + if current_user.role not in ["admin", "superadmin"]: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="需要管理员权限", + ) + return current_user + +# 获取超级管理员用户 +async def get_superadmin_user(current_user: User = Depends(get_required_user)): + if current_user.role != "superadmin": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="需要超级管理员权限", + ) + return current_user + +# 检查路径是否为公开路径 +def is_public_path(path: str) -> bool: + path = path.rstrip('/') # 去除尾部斜杠以便于匹配 + for pattern in PUBLIC_PATHS: + if re.match(pattern, path): + return True + return False + +# 路径是否需要管理员权限 +ADMIN_PATHS = [ + r"^/admin/.*$", # 管理员接口 + r"^/data/.*$", # 数据操作接口,所有数据操作都需要管理员权限 + r"^/chat/set_default_agent$", # 设置默认智能体 + r"^/chat/models/update$" # 更新模型列表 +] + +# 检查路径是否需要管理员权限 +def is_admin_path(path: str) -> bool: + path = path.rstrip('/') # 去除尾部斜杠以便于匹配 + for pattern in ADMIN_PATHS: + if re.match(pattern, path): + return True + return False \ No newline at end of file diff --git a/server/utils/auth_utils.py b/server/utils/auth_utils.py new file mode 100644 index 000000000..18ce903a3 --- /dev/null +++ b/server/utils/auth_utils.py @@ -0,0 +1,75 @@ +import hashlib +import os +import jwt +from datetime import datetime, timedelta +from typing import Optional, Dict, Any + +# JWT配置 +JWT_SECRET_KEY = os.environ.get("JWT_SECRET_KEY", "yuxi_know_secure_key") +JWT_ALGORITHM = "HS256" +JWT_EXPIRATION = 24 * 60 * 60 # 24小时过期 + +class AuthUtils: + """认证工具类""" + + @staticmethod + def hash_password(password: str) -> str: + """使用SHA-256哈希密码""" + # 生成盐 + salt = os.urandom(32).hex() + # 哈希密码 + hashed = hashlib.sha256((password + salt).encode()).hexdigest() + # 返回格式: "哈希值:盐" + return f"{hashed}:{salt}" + + @staticmethod + def verify_password(stored_password: str, provided_password: str) -> bool: + """验证密码""" + # 分离哈希值和盐 + if ":" not in stored_password: + return False + + hashed, salt = stored_password.split(":") + + # 使用相同的盐哈希提供的密码 + check_hash = hashlib.sha256((provided_password + salt).encode()).hexdigest() + + # 比较哈希值 + return hashed == check_hash + + @staticmethod + def create_access_token(data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str: + """创建JWT访问令牌""" + to_encode = data.copy() + + # 设置过期时间 + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(seconds=JWT_EXPIRATION) + + to_encode.update({"exp": expire}) + + # 编码JWT + encoded_jwt = jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM) + return encoded_jwt + + @staticmethod + def decode_token(token: str) -> Optional[Dict[str, Any]]: + """解码验证JWT令牌""" + try: + payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM]) + return payload + except jwt.PyJWTError: + return None + + @staticmethod + def verify_access_token(token: str) -> Dict[str, Any]: + """验证访问令牌,如果无效则抛出异常""" + try: + payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM]) + return payload + except jwt.ExpiredSignatureError: + raise ValueError("令牌已过期") + except jwt.InvalidTokenError: + raise ValueError("无效的令牌") \ No newline at end of file diff --git a/src/config/__init__.py b/src/config/__init__.py index b0df13178..99969c385 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -47,6 +47,8 @@ def __init__(self): self.add_item("enable_knowledge_base", default=False, des="是否开启知识库") self.add_item("enable_knowledge_graph", default=False, des="是否开启知识图谱") self.add_item("enable_web_search", default=False, des="是否开启网页搜索(注:现阶段会根据 TAVILY_API_KEY 自动开启,无法手动配置,将会在下个版本移除此配置项)") + # 默认智能体配置 + self.add_item("default_agent_id", default="", des="默认智能体ID") # 模型配置 ## 注意这里是模型名,而不是具体的模型路径,默认使用 HuggingFace 的路径 ## 如果需要自定义本地模型路径,则在 src/.env 中配置 MODEL_DIR diff --git a/web/src/apis/admin_api.js b/web/src/apis/admin_api.js new file mode 100644 index 000000000..5b4177cea --- /dev/null +++ b/web/src/apis/admin_api.js @@ -0,0 +1,314 @@ +import { apiGet, apiPost, apiPut, apiDelete } from './base' +import { useUserStore } from '@/stores/user' + +/** + * 管理员API模块 + * 只有管理员和超级管理员可以访问的API + * 权限要求: admin 或 superadmin + * + * 注意: 请确保在使用这些API之前检查用户是否具有管理员权限 + */ + +// 检查当前用户是否有管理员权限 +const checkAdminPermission = () => { + const userStore = useUserStore() + if (!userStore.isAdmin) { + throw new Error('需要管理员权限') + } + return true +} + +// 检查当前用户是否有超级管理员权限 +const checkSuperAdminPermission = () => { + const userStore = useUserStore() + if (!userStore.isSuperAdmin) { + throw new Error('需要超级管理员权限') + } + return true +} + +// 用户管理API +export const userManagementApi = { + /** + * 获取用户列表 + * @returns {Promise} - 用户列表 + */ + getUsers: async () => { + checkAdminPermission() + return apiGet('/api/auth/users', {}, true) + }, + + /** + * 创建新用户 + * @param {Object} userData - 用户数据 + * @returns {Promise} - 创建结果 + */ + createUser: async (userData) => { + checkAdminPermission() + return apiPost('/api/auth/users', userData, {}, true) + }, + + /** + * 更新用户 + * @param {number} userId - 用户ID + * @param {Object} userData - 用户数据 + * @returns {Promise} - 更新结果 + */ + updateUser: async (userId, userData) => { + checkAdminPermission() + return apiPut(`/api/auth/users/${userId}`, userData, {}, true) + }, + + /** + * 删除用户 + * @param {number} userId - 用户ID + * @returns {Promise} - 删除结果 + */ + deleteUser: async (userId) => { + checkAdminPermission() + return apiDelete(`/api/auth/users/${userId}`, {}, true) + }, +} + +// 令牌管理API +export const tokenApi = { + /** + * 获取令牌列表 + * @param {string} agentId - 智能体ID + * @returns {Promise} - 令牌列表 + */ + getTokens: async (agentId) => { + checkAdminPermission() + return apiGet(`/api/admin/tokens?agent_id=${agentId}`, {}, true) + }, + + /** + * 创建新令牌 + * @param {string} agentId - 智能体ID + * @param {string} name - 令牌名称 + * @returns {Promise} - 创建结果 + */ + createToken: async (agentId, name) => { + checkAdminPermission() + return apiPost('/api/admin/tokens', { agent_id: agentId, name }, {}, true) + }, + + /** + * 删除令牌 + * @param {string} tokenId - 令牌ID + * @returns {Promise} - 删除结果 + */ + deleteToken: async (tokenId) => { + checkAdminPermission() + return apiDelete(`/api/admin/tokens/${tokenId}`, {}, true) + }, +} + +// 知识库管理API +export const knowledgeBaseApi = { + /** + * 获取所有知识库 + * @returns {Promise} - 知识库列表 + */ + getDatabases: async () => { + checkAdminPermission() + return apiGet('/api/data/', {}, true) + }, + + /** + * 创建知识库 + * @param {Object} databaseData - 知识库数据 + * @returns {Promise} - 创建结果 + */ + createDatabase: async (databaseData) => { + checkAdminPermission() + return apiPost('/api/data/', databaseData, {}, true) + }, + + /** + * 获取知识库详情 + * @param {string} dbId - 知识库ID + * @returns {Promise} - 知识库详情 + */ + getDatabaseInfo: async (dbId) => { + checkAdminPermission() + return apiGet(`/api/data/info?db_id=${dbId}`, {}, true) + }, + + /** + * 删除知识库 + * @param {string} dbId - 知识库ID + * @returns {Promise} - 删除结果 + */ + deleteDatabase: async (dbId) => { + checkAdminPermission() + return apiDelete(`/api/data/?db_id=${dbId}`, {}, true) + }, + + /** + * 上传文件到知识库 + * @param {FormData} formData - 包含文件的FormData + * @param {string} dbId - 知识库ID + * @returns {Promise} - 上传结果 + */ + uploadFile: async (formData, dbId) => { + checkAdminPermission() + return fetch(`/api/data/upload?db_id=${dbId}`, { + method: 'POST', + headers: { + ...useUserStore().getAuthHeaders() + }, + body: formData + }).then(res => res.json()) + }, + + /** + * 删除文件 + * @param {string} dbId - 知识库ID + * @param {string} fileId - 文件ID + * @returns {Promise} - 删除结果 + */ + deleteFile: async (dbId, fileId) => { + checkAdminPermission() + return apiDelete('/api/data/document', { + body: JSON.stringify({ db_id: dbId, file_id: fileId }) + }, true) + }, + + /** + * 将文件分块 + * @param {Object} data - 分块参数 + * @returns {Promise} - 分块结果 + */ + fileToChunk: async (data) => { + checkAdminPermission() + return apiPost('/api/data/file-to-chunk', data, {}, true) + }, + + /** + * 将分块添加到数据库 + * @param {Object} data - 包含db_id和file_chunks的数据 + * @returns {Promise} - 添加结果 + */ + addByChunks: async (data) => { + checkAdminPermission() + return apiPost('/api/data/add-by-chunks', data, {}, true) + }, + + /** + * 查询测试 + * @param {Object} data - 查询参数 + * @returns {Promise} - 查询结果 + */ + queryTest: async (data) => { + checkAdminPermission() + return apiPost('/api/data/query-test', data, {}, true) + }, +} + +// 图数据库管理API +export const graphApi = { + /** + * 获取图数据库状态 + * @returns {Promise} - 图数据库状态 + */ + getGraphInfo: async () => { + checkAdminPermission() + return apiGet('/api/data/graph', {}, true) + }, + + /** + * 获取节点 + * @param {string} dbName - 图数据库名称 + * @param {number} num - 节点数量 + * @returns {Promise} - 节点数据 + */ + getNodes: async (dbName, num) => { + checkAdminPermission() + return apiGet(`/api/data/graph/nodes?kgdb_name=${dbName}&num=${num}`, {}, true) + }, + + /** + * 查询实体 + * @param {string} entityName - 实体名称 + * @returns {Promise} - 查询结果 + */ + queryNode: async (entityName) => { + checkAdminPermission() + return apiGet(`/api/data/graph/node?entity_name=${entityName}`, {}, true) + }, + + /** + * 添加JSONL文件到图数据库 + * @param {string} filePath - 文件路径 + * @returns {Promise} - 添加结果 + */ + addByJsonl: async (filePath) => { + checkAdminPermission() + return apiPost('/api/data/graph/add-by-jsonl', { file_path: filePath }, {}, true) + }, + + /** + * 为未索引节点添加索引 + * @param {string} dbName - 图数据库名称 + * @returns {Promise} - 索引结果 + */ + indexNodes: async (dbName) => { + checkAdminPermission() + return apiPost('/api/data/graph/index-nodes', { kgdb_name: dbName }, {}, true) + }, +} + +// 系统配置API +export const systemConfigApi = { + /** + * 设置默认智能体 + * @param {string} agentId - 智能体ID + * @returns {Promise} - 设置结果 + */ + setDefaultAgent: async (agentId) => { + checkAdminPermission() + return apiPost('/api/chat/set_default_agent', { agent_id: agentId }, {}, true) + }, + + /** + * 获取系统配置 + * @returns {Promise} - 系统配置 + */ + getSystemConfig: async () => { + checkAdminPermission() + return apiGet('/api/config', {}, true) + }, + + /** + * 更新系统配置 + * @param {Object} config - 配置项 + * @returns {Promise} - 更新结果 + */ + updateSystemConfig: async (config) => { + checkAdminPermission() + return apiPut('/api/config', config, {}, true) + }, + + /** + * 重启服务 + * @returns {Promise} - 重启结果 + */ + restartServer: async () => { + checkSuperAdminPermission() + return apiPost('/api/restart', {}, {}, true) + } +} + +// 日志API +export const logApi = { + /** + * 获取系统日志 + * @param {Object} params - 日志查询参数 + * @returns {Promise} - 日志数据 + */ + getLogs: async (params = {}) => { + checkAdminPermission() + return apiGet('/api/admin/logs', { params }, true) + }, +} \ No newline at end of file diff --git a/web/src/apis/auth_api.js b/web/src/apis/auth_api.js new file mode 100644 index 000000000..f971d5c7e --- /dev/null +++ b/web/src/apis/auth_api.js @@ -0,0 +1,106 @@ +import { apiGet, apiPost, apiDelete } from './base' + +/** + * 需要用户认证的API模块 + * 用户必须登录才能访问的API + * 权限要求: 任何已登录用户(普通用户、管理员、超级管理员) + */ + +// 聊天相关API +export const chatApi = { + /** + * 发送聊天消息 + * @param {Object} params - 聊天参数 + * @returns {Promise} - 聊天响应流 + */ + sendMessage: (params) => { + return fetch('/api/chat/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(params), + }) + }, + + /** + * 简单聊天调用(非流式) + * @param {string} query - 查询内容 + * @returns {Promise} - 聊天响应 + */ + simpleCall: (query) => apiPost('/api/chat/call', { query }, {}, true), + + /** + * 获取默认智能体 + * @returns {Promise} - 默认智能体信息 + */ + getDefaultAgent: () => apiGet('/api/chat/default_agent', {}, true), + + /** + * 获取智能体列表 + * @returns {Promise} - 智能体列表 + */ + getAgents: () => apiGet('/api/chat/agent', {}, true), + + /** + * 获取单个智能体详情 + * @param {string} agentId - 智能体ID + * @returns {Promise} - 智能体详情 + */ + getAgentDetail: (agentId) => apiGet(`/api/chat/agent/${agentId}`, {}, true), + + /** + * 获取可用工具列表 + * @returns {Promise} - 工具列表 + */ + getTools: () => apiGet('/api/chat/tools', {}, true), + + /** + * 获取对话历史 + * @returns {Promise} - 对话历史列表 + */ + getConversations: () => apiGet('/api/chat/conversations', {}, true), + + /** + * 获取特定对话 + * @param {string} conversationId - 对话ID + * @returns {Promise} - 对话详情 + */ + getConversation: (conversationId) => + apiGet(`/api/chat/conversations/${conversationId}`, {}, true), + + /** + * 删除对话 + * @param {string} conversationId - 对话ID + * @returns {Promise} - 删除结果 + */ + deleteConversation: (conversationId) => + apiDelete(`/api/chat/conversations/${conversationId}`, {}, true), + + /** + * 更新对话标题 + * @param {string} conversationId - 对话ID + * @param {string} title - 新标题 + * @returns {Promise} - 更新结果 + */ + updateConversationTitle: (conversationId, title) => + apiPost(`/api/chat/conversations/${conversationId}/title`, { title }, {}, true), +} + +// 用户设置API +export const userSettingsApi = { + /** + * 获取用户设置 + * @returns {Promise} - 用户设置 + */ + getSettings: () => apiGet('/api/user/settings', {}, true), + + /** + * 更新用户设置 + * @param {Object} settings - 新设置 + * @returns {Promise} - 更新结果 + */ + updateSettings: (settings) => apiPost('/api/user/settings', settings, {}, true), +} + +// 其他需要用户认证的API可以继续添加到这里 \ No newline at end of file diff --git a/web/src/apis/base.js b/web/src/apis/base.js new file mode 100644 index 000000000..78e4bdf82 --- /dev/null +++ b/web/src/apis/base.js @@ -0,0 +1,142 @@ +import { useUserStore } from '@/stores/user' +import { message } from 'ant-design-vue' + +/** + * 基础API请求封装 + * 提供统一的请求方法,自动处理认证头和错误 + */ + +/** + * 发送API请求的基础函数 + * @param {string} url - API端点 + * @param {Object} options - 请求选项 + * @param {boolean} requiresAuth - 是否需要认证头 + * @returns {Promise} - 请求结果 + */ +export async function apiRequest(url, options = {}, requiresAuth = false) { + try { + // 默认请求配置 + const requestOptions = { + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + } + + // 如果需要认证,添加认证头 + if (requiresAuth) { + const userStore = useUserStore() + if (!userStore.isLoggedIn) { + throw new Error('用户未登录') + } + + Object.assign(requestOptions.headers, userStore.getAuthHeaders()) + } + + // 发送请求 + const response = await fetch(url, requestOptions) + + // 处理API返回的错误 + if (!response.ok) { + // 尝试解析错误信息 + let errorMessage = `请求失败: ${response.status}` + try { + const errorData = await response.json() + errorMessage = errorData.detail || errorData.message || errorMessage + } catch (e) { + // 如果无法解析JSON,使用默认错误信息 + } + + // 特殊处理401和403错误 + if (response.status === 401) { + // 如果是认证失败,可能需要重新登录 + const userStore = useUserStore() + if (userStore.isLoggedIn) { + // 如果用户认为自己已登录,但收到401,则可能是令牌过期 + message.error('登录已过期,请重新登录') + userStore.logout() + window.location.href = '/login' + } + throw new Error('未授权,请先登录') + } else if (response.status === 403) { + throw new Error('没有权限执行此操作') + } + + throw new Error(errorMessage) + } + + // 检查Content-Type以确定如何处理响应 + const contentType = response.headers.get('Content-Type') + if (contentType && contentType.includes('application/json')) { + return await response.json() + } + + return await response.text() + } catch (error) { + console.error('API请求错误:', error) + throw error + } +} + +/** + * 发送GET请求 + * @param {string} url - API端点 + * @param {Object} options - 请求选项 + * @param {boolean} requiresAuth - 是否需要认证 + * @returns {Promise} - 请求结果 + */ +export function apiGet(url, options = {}, requiresAuth = false) { + return apiRequest(url, { method: 'GET', ...options }, requiresAuth) +} + +/** + * 发送POST请求 + * @param {string} url - API端点 + * @param {Object} data - 请求体数据 + * @param {Object} options - 其他请求选项 + * @param {boolean} requiresAuth - 是否需要认证 + * @returns {Promise} - 请求结果 + */ +export function apiPost(url, data = {}, options = {}, requiresAuth = false) { + return apiRequest( + url, + { + method: 'POST', + body: JSON.stringify(data), + ...options + }, + requiresAuth + ) +} + +/** + * 发送PUT请求 + * @param {string} url - API端点 + * @param {Object} data - 请求体数据 + * @param {Object} options - 其他请求选项 + * @param {boolean} requiresAuth - 是否需要认证 + * @returns {Promise} - 请求结果 + */ +export function apiPut(url, data = {}, options = {}, requiresAuth = false) { + return apiRequest( + url, + { + method: 'PUT', + body: JSON.stringify(data), + ...options + }, + requiresAuth + ) +} + +/** + * 发送DELETE请求 + * @param {string} url - API端点 + * @param {Object} options - 请求选项 + * @param {boolean} requiresAuth - 是否需要认证 + * @returns {Promise} - 请求结果 + */ +export function apiDelete(url, options = {}, requiresAuth = false) { + return apiRequest(url, { method: 'DELETE', ...options }, requiresAuth) +} \ No newline at end of file diff --git a/web/src/apis/index.js b/web/src/apis/index.js new file mode 100644 index 000000000..ffa124ccb --- /dev/null +++ b/web/src/apis/index.js @@ -0,0 +1,33 @@ +/** + * API模块索引文件 + * 导出所有API模块,方便统一引入 + */ + +// 导出公共API模块 +export * from './public_api' + +// 导出需要用户认证的API模块 +export * from './auth_api' + +// 导出需要管理员权限的API模块 +export * from './admin_api' + +// 导出基础工具函数 +export { apiRequest, apiGet, apiPost, apiPut, apiDelete } from './base' + +/** + * 权限说明: + * + * 1. public_api.js: 不需要认证就可以访问的API + * - 登录、初始化管理员、获取公共配置等 + * + * 2. auth_api.js: 需要用户认证才能访问的API + * - 权限要求: 任何已登录用户(普通用户、管理员、超级管理员) + * - 聊天功能、个人设置等 + * + * 3. admin_api.js: 需要管理员权限才能访问的API + * - 权限要求: admin 或 superadmin + * - 用户管理、知识库管理、系统配置等 + * + * 注意:本模块已处理权限验证和请求头,使用时无需再手动添加认证头 + */ \ No newline at end of file diff --git a/web/src/apis/public_api.js b/web/src/apis/public_api.js new file mode 100644 index 000000000..88d759dea --- /dev/null +++ b/web/src/apis/public_api.js @@ -0,0 +1,59 @@ +import { apiGet, apiPost } from './base' + +/** + * 公共API模块 + * 包含所有不需要认证的公共接口 + */ + +// 登录相关API +export const authApi = { + /** + * 用户登录 + * @param {Object} credentials - 登录凭证 + * @returns {Promise} - 登录结果 + */ + login: (credentials) => { + const formData = new FormData() + formData.append('username', credentials.username) + formData.append('password', credentials.password) + + return apiRequest('/api/auth/token', { + method: 'POST', + body: formData + }, false) + }, + + /** + * 检查是否是首次运行 + * @returns {Promise} - 是否首次运行 + */ + checkFirstRun: () => apiGet('/api/auth/check-first-run'), + + /** + * 初始化管理员账户 + * @param {Object} adminData - 管理员账户数据 + * @returns {Promise} - 初始化结果 + */ + initializeAdmin: (adminData) => apiPost('/api/auth/initialize', adminData), +} + +// 配置相关API +export const configApi = { + /** + * 获取系统配置 + * @returns {Promise} - 系统配置 + */ + getConfig: () => apiGet('/api/config'), +} + +// 健康检查API +export const healthApi = { + /** + * 系统健康检查 + * @returns {Promise} - 健康检查结果 + */ + check: () => apiGet('/api/health'), +} + +// 从base.js导入apiRequest以支持FormData +import { apiRequest } from './base' \ No newline at end of file diff --git a/web/src/components/AgentChatComponent.vue b/web/src/components/AgentChatComponent.vue index 5272d74be..6ca3c1b09 100644 --- a/web/src/components/AgentChatComponent.vue +++ b/web/src/components/AgentChatComponent.vue @@ -110,6 +110,8 @@ import { import { message } from 'ant-design-vue'; import MessageInputComponent from '@/components/MessageInputComponent.vue' import MessageComponent from '@/components/MessageComponent.vue' +import { useUserStore } from '@/stores/user' +import { chatApi } from '@/apis/auth_api' // 新增props属性,允许父组件传入agentId const props = defineProps({ @@ -127,6 +129,9 @@ const props = defineProps({ } }); +// 初始化userStore +const userStore = useUserStore(); + // ==================== 状态管理 ==================== // UI状态 @@ -356,7 +361,10 @@ const sendMessageWithText = async (text) => { // 发送请求 const response = await fetch(`/api/chat/agent/${currentAgent.value.name}`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + ...userStore.getAuthHeaders() + }, body: JSON.stringify(requestData) }); @@ -752,18 +760,13 @@ const appendToolMessageToExistingAssistant = async (data) => { // 获取智能体列表 const fetchAgents = async () => { try { - const response = await fetch('/api/chat/agent'); - if (response.ok) { - const data = await response.json(); - // 将数组转换为对象 - agents.value = data.agents.reduce((acc, agent) => { - acc[agent.name] = agent; - return acc; - }, {}); - console.log("agents", agents.value); - } else { - console.error('获取智能体失败'); - } + const data = await chatApi.getAgents(); + // 将数组转换为对象 + agents.value = data.agents.reduce((acc, agent) => { + acc[agent.name] = agent; + return acc; + }, {}); + console.log("agents", agents.value); } catch (error) { console.error('获取智能体错误:', error); } diff --git a/web/src/components/ChatComponent.vue b/web/src/components/ChatComponent.vue index 6ef374008..b314cfc4a 100644 --- a/web/src/components/ChatComponent.vue +++ b/web/src/components/ChatComponent.vue @@ -184,10 +184,12 @@ import { } from '@ant-design/icons-vue' import { onClickOutside } from '@vueuse/core' import { useConfigStore } from '@/stores/config' +import { useUserStore } from '@/stores/user' import { message } from 'ant-design-vue' import MessageInputComponent from '@/components/MessageInputComponent.vue' import MessageComponent from '@/components/MessageComponent.vue' import RefsSidebar from '@/components/RefsSidebar.vue' +import { chatApi } from '@/apis/auth_api' const props = defineProps({ conv: Object, @@ -196,6 +198,7 @@ const props = defineProps({ const emit = defineEmits(['rename-title', 'newconv']); const configStore = useConfigStore() +const userStore = useUserStore() const { conv, state } = toRefs(props) const chatContainer = ref(null) @@ -475,50 +478,56 @@ const groupRefs = (id) => { scrollToBottom() } -const simpleCall = (msg) => { - return new Promise((resolve, reject) => { - fetch('/api/chat/call', { - method: 'POST', - body: JSON.stringify({ query: msg, }), - headers: { 'Content-Type': 'application/json' } - }) - .then((response) => response.json()) - .then((data) => resolve(data)) - .catch((error) => reject(error)) - }) -} - const loadDatabases = () => { - fetch('/api/data/', { method: "GET", }) + fetch('/api/data/', { + method: "GET", + headers: userStore.getAuthHeaders() + }) .then(response => response.json()) .then(data => { console.log(data) opts.databases = data.databases }) + .catch(error => { + console.error('加载数据库列表失败:', error) + }) } -// 新函数用于处理 fetch 请求 +const simpleCall = (msg) => { + return new Promise((resolve, reject) => { + chatApi.simpleCall(msg) + .then(data => resolve(data)) + .catch(error => reject(error)) + }) +} + +// 替换fetchChatResponse函数 const fetchChatResponse = (user_input, cur_res_id) => { const controller = new AbortController(); const signal = controller.signal; const params = { query: user_input, - history: getHistory().slice(0, -1), // 去掉最后一条刚添加的用户消息, + history: getHistory().slice(0, -1), // 去掉最后一条刚添加的用户消息 meta: meta, cur_res_id: cur_res_id, } console.log(params) + // 使用fetch带上认证头和信号控制 fetch('/api/chat/', { method: 'POST', body: JSON.stringify(params), headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + ...userStore.getAuthHeaders() }, signal // 添加 signal 用于中断请求 }) .then((response) => { + if (!response.ok) { + throw new Error(`请求失败: ${response.status} ${response.statusText}`) + } if (!response.body) throw new Error("ReadableStream not supported."); const reader = response.body.getReader(); const decoder = new TextDecoder("utf-8"); @@ -587,6 +596,7 @@ const fetchChatResponse = (user_input, cur_res_id) => { updateMessage({ id: cur_res_id, status: "error", + message: error.message || '请求失败', }); } isStreaming.value = false; diff --git a/web/src/components/TokenManagerComponent.vue b/web/src/components/TokenManagerComponent.vue index 4b074f859..c29b7d4ea 100644 --- a/web/src/components/TokenManagerComponent.vue +++ b/web/src/components/TokenManagerComponent.vue @@ -61,6 +61,7 @@ import { ref, onMounted, watch } from 'vue'; import { message, Empty } from 'ant-design-vue'; import { PlusOutlined, DeleteOutlined, CopyOutlined } from '@ant-design/icons-vue'; +import { tokenApi } from '@/apis/admin_api'; const props = defineProps({ agentId: { @@ -81,16 +82,11 @@ const newToken = ref({ const fetchTokens = async () => { loading.value = true; try { - const response = await fetch(`/api/admin/tokens?agent_id=${props.agentId}`); - if (response.ok) { - const data = await response.json(); - tokens.value = data; - } else { - message.error('获取令牌列表失败'); - } + const data = await tokenApi.getTokens(props.agentId); + tokens.value = data; } catch (error) { console.error('获取令牌列表出错:', error); - message.error('获取令牌列表出错'); + message.error(error.message || '获取令牌列表出错'); } finally { loading.value = false; } @@ -104,48 +100,26 @@ const createToken = async () => { } try { - const response = await fetch('/api/admin/tokens', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - agent_id: props.agentId, - name: newToken.value.name - }) - }); - - if (response.ok) { - const data = await response.json(); - tokens.value.push(data); - message.success('令牌创建成功'); - addTokenModalVisible.value = false; - newToken.value.name = ''; - } else { - message.error('创建令牌失败'); - } + const data = await tokenApi.createToken(props.agentId, newToken.value.name); + tokens.value.push(data); + message.success('令牌创建成功'); + addTokenModalVisible.value = false; + newToken.value.name = ''; } catch (error) { console.error('创建令牌出错:', error); - message.error('创建令牌出错'); + message.error(error.message || '创建令牌出错'); } }; // 删除令牌 const deleteToken = async (tokenId) => { try { - const response = await fetch(`/api/admin/tokens/${tokenId}`, { - method: 'DELETE' - }); - - if (response.ok) { - tokens.value = tokens.value.filter(token => token.id !== tokenId); - message.success('令牌已删除'); - } else { - message.error('删除令牌失败'); - } + await tokenApi.deleteToken(tokenId); + tokens.value = tokens.value.filter(token => token.id !== tokenId); + message.success('令牌已删除'); } catch (error) { console.error('删除令牌出错:', error); - message.error('删除令牌出错'); + message.error(error.message || '删除令牌出错'); } }; diff --git a/web/src/components/UserInfoComponent.vue b/web/src/components/UserInfoComponent.vue new file mode 100644 index 000000000..9afe0d941 --- /dev/null +++ b/web/src/components/UserInfoComponent.vue @@ -0,0 +1,139 @@ + + + + + \ No newline at end of file diff --git a/web/src/layouts/AppLayout.vue b/web/src/layouts/AppLayout.vue index e29115ce1..e17bf6b34 100644 --- a/web/src/layouts/AppLayout.vue +++ b/web/src/layouts/AppLayout.vue @@ -29,6 +29,8 @@ import { themeConfig } from '@/assets/theme' import { useConfigStore } from '@/stores/config' import { useDatabaseStore } from '@/stores/database' import DebugComponent from '@/components/DebugComponent.vue' +import UserInfoComponent from '@/components/UserInfoComponent.vue' +import { configApi } from '@/apis/public_api' const configStore = useConfigStore() const databaseStore = useDatabaseStore() @@ -57,11 +59,12 @@ const getRemoteDatabase = () => { const fetchGithubStars = async () => { try { isLoadingStars.value = true + // 公共API,可以直接使用fetch const response = await fetch('https://api.github.com/repos/xerrors/Yuxi-Know') const data = await response.json() githubStars.value = data.stargazers_count } catch (error) { - console.error('Error fetching GitHub stars:', error) + console.error('获取GitHub stars失败:', error) } finally { isLoadingStars.value = false } @@ -102,8 +105,8 @@ const mainList = [{ activeIcon: BookFilled, // hidden: !configStore.config.enable_knowledge_base, }, { - name: '工具', - path: '/tools', + name: '智能体', + path: '/agent', icon: ToolOutlined, activeIcon: ToolFilled, } @@ -163,6 +166,10 @@ const mainList = [{
+ + + +