From b96641459a23b394a4d2789073ff6cb7e8f0442c Mon Sep 17 00:00:00 2001 From: root Date: Thu, 20 Aug 2026 20:17:34 +0800 Subject: [PATCH] =?utf8?q?AI=20=E5=90=84=E9=A1=B9=E5=8A=9F=E8=83=BD?= =?utf8?q?=E5=B9=B6=E5=8F=91=E8=B0=83=E7=94=A8=E6=95=B0=E7=BB=9F=E4=B8=80?= =?utf8?q?=E9=99=90=E5=88=B6=E4=B8=BA=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - db-sidecar.mjs:新增全局信号量 AI_CONCURRENCY=2 包裹 runCodebuddy, 使站点生成(含批内并行)、各项补全、领域方案补全全部 AI 功能任意时刻最多 2 个 codebuddy 子进程并发;release 在 close/error/超时 三处统一释放并加 released 守卫与同步 spawn 失败保护,避免死锁。 - 站点「生成全部」批内并行数 GEN_CONCURRENCY 由硬编码 3 改为复用 AI_CONCURRENCY, 对应日志文案同步为「最多 2 个并行调用」。 - ai-sidecar.mjs(/api/chat) 本身以 running 布尔量串行(≤1),已满足 ≤2。 - design-doc.html 升 v0.24 并登记变更。 - 注:未提交 data/db/StationBuilder.sqlite(无 schema 变更,且工作库含累积业务数据)。 --- db-sidecar.mjs | 38 ++++++++++++++++++++++++++++++++------ public/design-doc.html | 3 ++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/db-sidecar.mjs b/db-sidecar.mjs index 0f15f23..de47d96 100644 --- a/db-sidecar.mjs +++ b/db-sidecar.mjs @@ -628,7 +628,25 @@ function repairAndValidate(json) { return { ok: errors.length === 0, json: fixed, errors }; } -function runCodebuddy(prompt, sessionId, onEvent) { +// 全局 AI 并发上限:任意时刻最多 AI_CONCURRENCY 个 codebuddy 子进程并发, +// 覆盖站点生成(含批内并行)、各项补全、领域方案补全——即 StationBuilder 全部 AI 功能。 +const AI_CONCURRENCY = 2; +const aiSem = { active: 0, waiters: [] }; +function aiAcquire() { + return new Promise((resolve) => { + if (aiSem.active < AI_CONCURRENCY) { aiSem.active++; resolve(); } + else aiSem.waiters.push(resolve); + }); +} +function aiRelease() { + if (aiSem.active > 0) aiSem.active--; + if (aiSem.waiters.length) { aiSem.active++; aiSem.waiters.shift()(); } +} + +async function runCodebuddy(prompt, sessionId, onEvent) { + await aiAcquire(); + let released = false; + const release = () => { if (!released) { released = true; aiRelease(); } }; return new Promise((resolve, reject) => { const args = [ "--model", "hy3", @@ -640,11 +658,18 @@ function runCodebuddy(prompt, sessionId, onEvent) { "--tools", "", "-y", ]; - const child = spawn(CODEBUDDY, args, { env: process.env, cwd: CWD }); + let child; + try { + child = spawn(CODEBUDDY, args, { env: process.env, cwd: CWD }); + } catch (e) { + release(); + return reject(e); + } let buf = ""; let fullText = ""; const timer = setTimeout(() => { child.kill("SIGKILL"); + release(); reject(new Error("codebuddy 生成超时(>480s)")); }, 480000); const push = (line) => { @@ -666,10 +691,11 @@ function runCodebuddy(prompt, sessionId, onEvent) { } }); child.stderr.on("data", c => push(c.toString("utf-8"))); - child.on("error", reject); + child.on("error", (e) => { release(); reject(e); }); child.on("close", code => { clearTimeout(timer); if (buf.trim()) push(buf); + release(); if (code && code !== 0) return reject(new Error("codebuddy exit " + code)); resolve(fullText); }); @@ -1516,10 +1542,10 @@ async function handleGenerateAll(req, res, siteId) { streamEvent(res, { log: o.event.delta.text }); } }; - streamEvent(res, { log: `\n▶ 开始站点生成:最多 3 个并行调用 Wordbuddy AI(Hy3)与 dashboard-json-generator Skill 生成 ${cubes.length} 个 Cube 页面…\n` }); + streamEvent(res, { log: `\n▶ 开始站点生成:最多 ${AI_CONCURRENCY} 个并行调用 Wordbuddy AI(Hy3)与 dashboard-json-generator Skill 生成 ${cubes.length} 个 Cube 页面…\n` }); streamEvent(res, { task: "模型准备", status: "done" }); - // ⑥ 并发生成:各 Cube 互为独立,但限制最多 3 个同时进行,避免资源争抢导致超时。 - const GEN_CONCURRENCY = 3; + // ⑥ 并发生成:各 Cube 互为独立,但限制最多 AI_CONCURRENCY 个同时进行,避免资源争抢导致超时(全局 AI 并发上限见 runCodebuddy)。 + const GEN_CONCURRENCY = AI_CONCURRENCY; const onLog = (t) => streamEvent(res, { log: t }); await mapWithConcurrency(cubes, GEN_CONCURRENCY, async (cube) => { streamEvent(res, { task: cube.name, status: "running" }); diff --git a/public/design-doc.html b/public/design-doc.html index 051c4d3..319aff9 100644 --- a/public/design-doc.html +++ b/public/design-doc.html @@ -115,7 +115,7 @@
-

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

+

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

StationBuilder 产品与交互设计方案

1. 文档说明

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

11.1 版本变更记录(Changelog)

+ -- 2.43.0
版本日期修改人说明
v0.242026-08-20wang.yuAI 并发调用统一限流:新增全局信号量 AI_CONCURRENCY = 2,包裹 runCodebuddy(db-sidecar.mjs),使站点生成(含批内并行)、各项补全(complete / complete-assets / complete-cubes)、领域方案补全(dt-complete 系列)等全部 AI 功能任意时刻最多 2 个 codebuddy 子进程并发,避免无脑全并行抢占资源导致超时。站点「生成全部」批内并行数 GEN_CONCURRENCY 由硬编码 3 改为复用 AI_CONCURRENCY,对应日志文案同步为「最多 2 个并行调用」。AI 聊天侧(ai-sidecar.mjs /api/chat)本身以 running 布尔量串行(同一时刻仅 1 个),已满足 ≤2。
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 主题,无需改动提示词构造。