From: root Date: Thu, 20 Aug 2026 11:23:37 +0000 (+0800) Subject: 领域知识上传支持 Word/Excel/PDF/图片:提取正文注入提示词 X-Git-Url: http://acesimba.cloud/gitweb/?a=commitdiff_plain;h=d29c3e8048843fbffb1f62a00a7aa5c846cab291;p=StationBuilder.git 领域知识上传支持 Word/Excel/PDF/图片:提取正文注入提示词 - 后端 db-sidecar.mjs:新增 async extractDocText 替换 isTextMime/readKnowledgeFile, PDF(pdf-parse)/Word(.docx,mammoth)/Excel(.xls/.xlsx,SheetJS) 提取正文并 16k 截断注入, 图片及老 .doc 返回空串仅登记为参考来源;buildKnowledgePrompt 改为 await extractDocText。 - 前端 KnowledgeStep:上传 accept 放开至 .pdf/.doc/.docx/.xls/.xlsx/image/* 等, 提示文案补充「Word/Excel/PDF 提取正文,图片仅登记」,文件类徽标「文档」→「文件」。 - 新增依赖 pdf-parse/mammoth/xlsx(纯 JS,无原生编译)。 - design-doc.html 升 v0.23 并登记变更。 --- diff --git a/app/page.tsx b/app/page.tsx index e1aee99..94ab8ca 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1790,10 +1790,10 @@ function KnowledgeStep({id,docs,notify,reload,confirm}:{id:number;docs:any[];not const removeDoc=async(docId:number)=>{ if(!(await confirm("确定删除该知识来源?此操作不可恢复"))) return; try{ await fetchDb(`/knowledge-docs/${docId}`,{method:"DELETE"}); notify("已删除"); reload(); }catch(e:any){ notify("删除失败:"+(e?.message||e)); } }; return
上传中…:undefined}> -

上传与本站领域相关的文档(标准规范、设备手册、工艺说明、建设方案等)。知识文本将作为资产配置、功能菜单 AI 补全的优先参考资料,并随方案保存。支持 txt / md / json / csv / html 等文本类,其他格式将作为参考资料登记。

+

上传与本站领域相关的文档(标准规范、设备手册、工艺说明、建设方案等)。知识文本将作为资产配置、功能菜单 AI 补全的优先参考资料,并随方案保存。支持 Word / Excel / PDF / 图片及常见文本格式;Word、Excel、PDF 会提取正文注入,图片仅作参考登记。

@@ -1809,7 +1809,7 @@ function KnowledgeStep({id,docs,notify,reload,confirm}:{id:number;docs:any[];not {docs.map((d:any)=> - + diff --git a/db-sidecar.mjs b/db-sidecar.mjs index ff3c8d6..0f15f23 100644 --- a/db-sidecar.mjs +++ b/db-sidecar.mjs @@ -9,6 +9,9 @@ import { existsSync, mkdirSync, readFileSync } from "node:fs"; import { dirname, join, basename, extname } from "node:path"; import { fileURLToPath } from "node:url"; import { randomUUID } from "node:crypto"; +import mammoth from "mammoth"; +import * as XLSX from "xlsx"; +import { PDFParse } from "pdf-parse"; const PORT = 37823; const PROJECT_DIR = dirname(fileURLToPath(import.meta.url)); @@ -1111,18 +1114,59 @@ async function handleRefineCube(req, res, siteId, cubeId) { // ===== AI 智能补全:基于站点名称/领域/描述分析并生成「补充描述」 ===== // ===== 领域知识范本:从本方案已上传/配置的领域知识(文档 / URL 站点)中抽取可注入提示词的文本 ===== - function isTextMime(mime, filename) { - if (mime && String(mime).toLowerCase().startsWith("text/")) return true; - const ext = (filename || "").toLowerCase().split(".").pop(); - return [".txt", ".md", ".markdown", ".json", ".csv", ".log", ".html", ".xml", ".yaml", ".yml"].includes("." + ext); + // 文本类(txt/md/json/csv/html/xml/yaml/yml)直接读取;pdf/docx/xls/xlsx 提取正文; + // 图片及无法提取的格式返回空串(buildKnowledgePrompt 中仍会登记为参考来源)。 + const TEXT_EXTS = [".txt", ".md", ".markdown", ".json", ".csv", ".log", ".html", ".htm", ".xml", ".yaml", ".yml", ".text"]; + const IMAGE_EXTS = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".svg", ".tiff", ".tif"]; + const MAX_KB_TEXT = 16000; + function truncateText(text) { + return text.length > MAX_KB_TEXT ? text.slice(0, MAX_KB_TEXT) + "\n…(内容已截断,原文较长)" : text; } - function readKnowledgeFile(filePath, mime, filename) { + async function extractDocText(filePath, mime, filename) { try { if (!filePath || !existsSync(filePath)) return ""; - if (!isTextMime(mime, filename)) return ""; - const text = readFileSync(filePath, "utf8"); - return text.length > 16000 ? text.slice(0, 16000) + "\n…(内容已截断,原文较长)" : text; - } catch { return ""; } + const ext = "." + String(filename || "").toLowerCase().split(".").pop(); + const lowerMime = String(mime || "").toLowerCase(); + + // 图片:仅登记,不提取 + if (lowerMime.startsWith("image/") || IMAGE_EXTS.includes(ext)) return ""; + + // 纯文本类:直接读取 + if (lowerMime.startsWith("text/") || TEXT_EXTS.includes(ext)) { + return truncateText(readFileSync(filePath, "utf8")); + } + + const buf = readFileSync(filePath); + // PDF + if (ext === ".pdf" || lowerMime === "application/pdf") { + const parser = new PDFParse({ data: buf }); + try { + const result = await parser.getText(); + return truncateText(result.text || ""); + } finally { + await parser.destroy().catch(() => {}); + } + } + // Word(仅 .docx;老 .doc 二进制无法纯 JS 提取,作为参考登记) + if (ext === ".docx" || lowerMime === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") { + const r = await mammoth.extractRawText({ buffer: buf }); + return truncateText(r.value || ""); + } + // Excel(.xls / .xlsx 均可由 SheetJS 读取) + if (ext === ".xls" || ext === ".xlsx" || lowerMime.includes("spreadsheet") || lowerMime.includes("excel")) { + const wb = XLSX.read(buf, { type: "buffer" }); + const parts = wb.SheetNames.map((name) => { + const csv = XLSX.utils.sheet_to_csv(wb.Sheets[name], { blankrows: false }); + return csv ? `【Sheet: ${name}】\n${csv}` : ""; + }).filter(Boolean); + return truncateText(parts.join("\n\n")); + } + + // 其它二进制(含老 .doc 等):仅登记,不提取 + return ""; + } catch { + return ""; + } } async function fetchKnowledgeUrl(url) { try { @@ -1146,7 +1190,7 @@ async function handleRefineCube(req, res, siteId, cubeId) { const parts = []; for (const d of docs) { let body = ""; - if (d.doc_type === "file") body = readKnowledgeFile(d.file_path, d.mime, d.name); + if (d.doc_type === "file") body = await extractDocText(d.file_path, d.mime, d.name); else if (d.doc_type === "link") body = await fetchKnowledgeUrl(d.url); if (body && body.trim()) parts.push(`【领域知识 · ${d.name}】\n${body.trim()}\n`); else parts.push(`(参考来源:${d.doc_type === "link" ? d.url : d.name})`); diff --git a/package-lock.json b/package-lock.json index acef960..60cc0a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,12 @@ "version": "0.1.0", "dependencies": { "drizzle-orm": "0.45.2", + "mammoth": "^1.12.1", "next": "16.2.6", + "pdf-parse": "^2.4.5", "react": "19.2.6", - "react-dom": "19.2.6" + "react-dom": "19.2.6", + "xlsx": "^0.18.5" }, "devDependencies": { "@cloudflare/vite-plugin": "1.37.1", @@ -2122,6 +2125,190 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas/-/canvas-0.1.80.tgz", + "integrity": "sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==", + "license": "MIT", + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.80", + "@napi-rs/canvas-darwin-arm64": "0.1.80", + "@napi-rs/canvas-darwin-x64": "0.1.80", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.80", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.80", + "@napi-rs/canvas-linux-arm64-musl": "0.1.80", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-musl": "0.1.80", + "@napi-rs/canvas-win32-x64-msvc": "0.1.80" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.80.tgz", + "integrity": "sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz", + "integrity": "sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz", + "integrity": "sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz", + "integrity": "sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz", + "integrity": "sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz", + "integrity": "sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz", + "integrity": "sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz", + "integrity": "sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz", + "integrity": "sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.80", + "resolved": "http://mirrors.tencent.com/npm/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz", + "integrity": "sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", @@ -3991,6 +4178,15 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.14", + "resolved": "http://mirrors.tencent.com/npm/@xmldom/xmldom/-/xmldom-0.8.14.tgz", + "integrity": "sha512-T4EDRUBVZYRldYApjEJiU0e1stYWaRAX7CuSnKzrpwdZKo53zGV8/pqfzV6FfwNl9YThD2OumQYvqtvjvgG7aQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4057,6 +4253,15 @@ "node": ">=0.4.0" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "http://mirrors.tencent.com/npm/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", @@ -4401,6 +4606,12 @@ "dev": true, "license": "MIT" }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "http://mirrors.tencent.com/npm/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", @@ -4556,6 +4767,19 @@ ], "license": "CC-BY-4.0" }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "http://mirrors.tencent.com/npm/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4590,6 +4814,14 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "http://mirrors.tencent.com/npm/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4646,6 +4878,24 @@ "url": "https://opencollective.com/express" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "http://mirrors.tencent.com/npm/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "http://mirrors.tencent.com/npm/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4846,6 +5096,12 @@ "node": ">=8" } }, + "node_modules/dingbat-to-unicode": { + "version": "1.0.1", + "resolved": "http://mirrors.tencent.com/npm/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz", + "integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==", + "license": "BSD-2-Clause" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -5484,6 +5740,15 @@ } } }, + "node_modules/duck": { + "version": "0.1.12", + "resolved": "http://mirrors.tencent.com/npm/duck/-/duck-0.1.12.tgz", + "integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==", + "license": "BSD", + "dependencies": { + "underscore": "^1.13.1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -6396,6 +6661,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "http://mirrors.tencent.com/npm/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -6767,6 +7041,12 @@ "node": ">=16.x" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "http://mirrors.tencent.com/npm/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -6794,6 +7074,12 @@ "node": ">=0.8.19" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "http://mirrors.tencent.com/npm/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -7392,6 +7678,24 @@ "node": ">=4.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "http://mirrors.tencent.com/npm/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/pako": { + "version": "1.0.11", + "resolved": "http://mirrors.tencent.com/npm/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7446,6 +7750,15 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "http://mirrors.tencent.com/npm/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lightningcss": { "version": "1.31.1", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", @@ -7769,6 +8082,17 @@ "loose-envify": "cli.js" } }, + "node_modules/lop": { + "version": "0.4.2", + "resolved": "http://mirrors.tencent.com/npm/lop/-/lop-0.4.2.tgz", + "integrity": "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==", + "license": "BSD-2-Clause", + "dependencies": { + "duck": "^0.1.12", + "option": "~0.2.1", + "underscore": "^1.13.1" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -7789,6 +8113,59 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mammoth": { + "version": "1.12.1", + "resolved": "http://mirrors.tencent.com/npm/mammoth/-/mammoth-1.12.1.tgz", + "integrity": "sha512-nCH9KKjWi3jQ+i8bUKs7k1yrXtSEGpWgF8IYkzsFMcbn+5S6l4bZEBbyx2hOQErFiXPuAs9RPa6qjXVxhyx/8g==", + "license": "BSD-2-Clause", + "dependencies": { + "@xmldom/xmldom": "^0.8.6", + "argparse": "~1.0.3", + "base64-js": "^1.5.1", + "bluebird": "~3.4.0", + "dingbat-to-unicode": "^1.0.1", + "jszip": "^3.7.1", + "lop": "^0.4.2", + "path-is-absolute": "^1.0.0", + "underscore": "^1.13.1", + "xmlbuilder": "^10.0.0" + }, + "bin": { + "mammoth": "bin/mammoth" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/mammoth/node_modules/argparse": { + "version": "1.0.10", + "resolved": "http://mirrors.tencent.com/npm/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/mammoth/node_modules/base64-js": { + "version": "1.5.1", + "resolved": "http://mirrors.tencent.com/npm/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -8171,6 +8548,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/option": { + "version": "0.2.4", + "resolved": "http://mirrors.tencent.com/npm/option/-/option-0.2.4.tgz", + "integrity": "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==", + "license": "BSD-2-Clause" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -8280,6 +8663,15 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "http://mirrors.tencent.com/npm/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8311,6 +8703,38 @@ "dev": true, "license": "MIT" }, + "node_modules/pdf-parse": { + "version": "2.4.5", + "resolved": "http://mirrors.tencent.com/npm/pdf-parse/-/pdf-parse-2.4.5.tgz", + "integrity": "sha512-mHU89HGh7v+4u2ubfnevJ03lmPgQ5WU4CxAVmTSh/sxVTEDYd1er/dKS/A6vg77NX47KTEoihq8jZBLr8Cxuwg==", + "license": "Apache-2.0", + "dependencies": { + "@napi-rs/canvas": "0.1.80", + "pdfjs-dist": "5.4.296" + }, + "bin": { + "pdf-parse": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.16.0 <21 || >=22.3.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/mehmet-kozan" + } + }, + "node_modules/pdfjs-dist": { + "version": "5.4.296", + "resolved": "http://mirrors.tencent.com/npm/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", + "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.16.0 || >=22.3.0" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.80" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -8386,6 +8810,12 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "http://mirrors.tencent.com/npm/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -8477,6 +8907,27 @@ "webpack": "^5.59.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "http://mirrors.tencent.com/npm/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "http://mirrors.tencent.com/npm/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -8665,6 +9116,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "http://mirrors.tencent.com/npm/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -8849,6 +9306,12 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "http://mirrors.tencent.com/npm/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/sharp": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", @@ -9036,6 +9499,11 @@ "source-map": "^0.6.0" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "http://mirrors.tencent.com/npm/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, "node_modules/srvx": { "version": "0.11.15", "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.15.tgz", @@ -9049,6 +9517,18 @@ "node": ">=20.16.0" } }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "http://mirrors.tencent.com/npm/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -9070,6 +9550,15 @@ "node": ">= 0.4" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "http://mirrors.tencent.com/npm/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string.prototype.codepointat": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", @@ -9693,6 +10182,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "http://mirrors.tencent.com/npm/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "license": "MIT" + }, "node_modules/undici": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz", @@ -9814,6 +10309,12 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "http://mirrors.tencent.com/npm/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/vinext": { "version": "0.0.50", "resolved": "https://registry.npmjs.org/vinext/-/vinext-0.0.50.tgz", @@ -10518,6 +11019,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "http://mirrors.tencent.com/npm/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "http://mirrors.tencent.com/npm/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -11090,6 +11609,36 @@ } } }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "http://mirrors.tencent.com/npm/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xmlbuilder": { + "version": "10.1.1", + "resolved": "http://mirrors.tencent.com/npm/xmlbuilder/-/xmlbuilder-10.1.1.tgz", + "integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 955bcb5..86f4ec2 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,12 @@ }, "dependencies": { "drizzle-orm": "0.45.2", + "mammoth": "^1.12.1", "next": "16.2.6", + "pdf-parse": "^2.4.5", "react": "19.2.6", - "react-dom": "19.2.6" + "react-dom": "19.2.6", + "xlsx": "^0.18.5" }, "devDependencies": { "@cloudflare/vite-plugin": "1.37.1", diff --git a/public/design-doc.html b/public/design-doc.html index 322ed12..051c4d3 100644 --- a/public/design-doc.html +++ b/public/design-doc.html @@ -115,7 +115,7 @@
-

文档版本:v0.22 最后更新:2026-08-20 修改人:wang.yu 状态:开发中(演示数据已标注)

+

文档版本:v0.23 最后更新:2026-08-20 修改人:wang.yu 状态:开发中(演示数据已标注)

StationBuilder 产品与交互设计方案

1. 文档说明

@@ -753,6 +753,7 @@

11.1 版本变更记录(Changelog)

名称类型大小创建时间操作
{d.name}{d.doc_type==="link"?"URL 站点":"文档"}{d.doc_type==="link"?"URL 站点":"文件"} {d.size!=null?`${Math.round(Number(d.size)/1024*10)/10} KB`:"—"} {d.created_at||""} {d.doc_type==="file"&&下载}
+
版本日期修改人说明
v0.232026-08-20wang.yu领域知识上传格式扩展:KnowledgeStep 上传 accept 由纯文本类放开至 Word / Excel / PDF / 图片及常见文本(.pdf,.doc,.docx,.xls,.xlsx,image/* 等);提示文案补充「Word、Excel、PDF 会提取正文注入,图片仅作参考登记」,列表文件类徽标「文档」改为「文件」以兼容图片。后端 extractDocText(filePath,mime,filename) 替换原 isTextMime/readKnowledgeFile:文本类(txt/md/json/csv/html/xml/yaml/yml 等)直接读取;PDF(pdf-parse)、Word(仅 .docx,mammoth)、Excel(.xls/.xlsx,SheetJS 转 CSV)提取正文并 16k 截断后注入提示词;图片及老 .doc 等无法纯 JS 提取的格式返回空串,buildKnowledgePrompt 中仍登记为参考来源((参考来源:文件名))。新增依赖 pdf-parse / mammoth / xlsx(纯 JS,无原生编译)。
v0.222026-08-20wang.yu领域知识提升为方案创建流程 Step 2,并作为 AI 补全的优先参考资料:① 方案向导步骤重排——领域知识由末段移至「方案基本属性」之后(Step 2),原 资产设置 / 功能与菜单 / 运维流程 / 生成保存 / 专家确认 整体后移一位(DOMAIN_STEPS 顺序调整,key 不变,步进导航自动适配)。② 新增「领域知识」步骤(KnowledgeStep):支持「上传领域知识文档」(多文件,base64 经既有 POST /api/domain-templates/:id/docs 落库,文本类读正文、其他格式登记为参考)与「配置参考 URL 站点」(doc_type=link),列表展示名称/类型/大小/时间并提供「下载」(仅文档)与「删除」(DELETE /api/knowledge-docs/:id,同步清理磁盘文件);知识随方案持久化、可删。③ 知识驱动 AI 补全:新增 buildKnowledgePrompt(ctx)(镜像 buildStylePrompt),读取本方案 knowledge_docs——文本文档直接注入正文、URL 站点由服务端 fetch 抓取正文注入(8s 超时,失败降级为仅保留 URL 链接作为参考),注入到 buildCompletePrompt / buildCompleteAssetsPrompt / buildCompleteCubesPrompt 三处(三个构建器改为 async、8 处调用点加 await;领域级补全 ctx 增加 id,站点级无 id 不注入)。优先级为「优先依据已上传领域知识分析补全,再做大模型在线补充」。④ 生成保存(DomainGenerateReview)「领域知识」行由「(待开发)」改为真实文档信息(份数 + 名称列举),并提供「返回领域知识」快捷入口;运维流程 AI 补全本期仍占位(尚未实现)。
v0.212026-08-20wang.yu领域方案库 Cube 扩展页面支持选择页面样式库样式后生成(镜像站点侧 sites.style_id 机制,方案级):① 后端 domain_templates 新增 style_id 列(ensureColumn 增量加列);handleDomainTemplateUpdate 支持写入/显式置空;hydrateDomainTemplateCtx 返回真实 style_id(此前硬编码 null)。② 前端领域方案详情「功能与菜单 → Cube 扩展页面」顶部新增「领域方案页面样式」选择器(复用 .style-picker 与页面样式库缩略图),选中即 PUT /domain-templates/:id 持久化;生成/AI 修改经共享的 buildStylePrompt 自动注入所选样式的 JSON 主题,无需改动提示词构造。
v0.202026-08-20wang.yu领域分类管理增强:① 默认分类调整——移除「工业制造 / 工业园区 / 智慧楼宇」,新增「其他」(DEFAULT_DOMAINS 同步更新,重启不再复活被删分类);② 领域方案库新增「管理领域」面板,列出全部领域及其方案数,「其他」标注「默认保留」且不可删除,其余领域提供「删除」按钮,经自定义确认弹窗二次确认后调用 DELETE /api/domains/:id;③ 后端新增 DELETE /api/domains/:id:禁止删除「其他」,删除前将待删领域的 domain_templates 与 device_template_domains 关联迁移至「其他」(避免 ON DELETE CASCADE 误删方案),再删除领域;④ 删除后前端刷新领域列表,并在当前筛选命中该领域时自动清除筛选。