From 1bf18c03ce3a7cc2efc5d170e9eaff94074983b4 Mon Sep 17 00:00:00 2001 From: "wang.yu" Date: Tue, 18 Aug 2026 11:38:33 +0800 Subject: [PATCH] =?utf8?q?=E6=95=B4=E7=AB=99=E7=94=9F=E6=88=90=E9=99=90?= =?utf8?q?=E5=88=B6=E6=9C=80=E5=A4=9A3=E4=B8=AA=E5=B9=B6=E5=8F=91=EF=BC=8C?= =?utf8?q?=E9=81=BF=E5=85=8D=E8=B5=84=E6=BA=90=E4=BA=89=E6=8A=A2=E5=AF=BC?= =?utf8?q?=E8=87=B4=E8=B6=85=E6=97=B6=EF=BC=9B=E5=A4=B1=E8=B4=A5=E4=BB=85?= =?utf8?q?=E6=8F=90=E7=A4=BA=E6=89=8B=E5=8A=A8=E9=87=8D=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- db-sidecar.mjs | 25 ++++++++++++++++++++----- public/design-doc.html | 3 ++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/db-sidecar.mjs b/db-sidecar.mjs index d18f8de..e186bff 100644 --- a/db-sidecar.mjs +++ b/db-sidecar.mjs @@ -1091,6 +1091,20 @@ ${assetText} return respondJson(res, 200, { prompt: buildCompleteCubesPrompt(ctx) }); } + // 并发上限执行:最多同时跑 limit 个任务,避免无脑全并行抢占资源导致超时 + async function mapWithConcurrency(items, limit, fn) { + const results = new Array(items.length); + let cursor = 0; + const worker = async () => { + while (cursor < items.length) { + const i = cursor++; + results[i] = await fn(items[i], i); + } + }; + await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker)); + return results; + } + async function handleGenerateAll(req, res, siteId) { res.writeHead(200, { "Content-Type": "application/x-ndjson; charset=utf-8", "Cache-Control": "no-cache" }); if (genLocks.has(`site-${siteId}`)) { @@ -1121,11 +1135,12 @@ async function handleGenerateAll(req, res, siteId) { streamEvent(res, { log: o.event.delta.text }); } }; - streamEvent(res, { log: `\n▶ 开始站点生成:并行调用 Wordbuddy AI(Hy3)与 dashboard-json-generator Skill 生成 ${cubes.length} 个 Cube 页面…\n` }); + streamEvent(res, { log: `\n▶ 开始站点生成:最多 3 个并行调用 Wordbuddy AI(Hy3)与 dashboard-json-generator Skill 生成 ${cubes.length} 个 Cube 页面…\n` }); streamEvent(res, { task: "模型准备", status: "done" }); - // ⑥ 并行生成:各 Cube 互为独立,使用 Promise.all 并发调用,显著缩短整站生成耗时。 + // ⑥ 并发生成:各 Cube 互为独立,但限制最多 3 个同时进行,避免资源争抢导致超时。 + const GEN_CONCURRENCY = 3; const onLog = (t) => streamEvent(res, { log: t }); - await Promise.all(cubes.map(async (cube) => { + await mapWithConcurrency(cubes, GEN_CONCURRENCY, async (cube) => { streamEvent(res, { task: cube.name, status: "running" }); streamEvent(res, { log: `\n▶ 调用 Cube Skill(dashboard-json-generator)生成「${cube.name}」…\n` }); try { @@ -1144,9 +1159,9 @@ async function handleGenerateAll(req, res, siteId) { } catch (e) { db.prepare("UPDATE cubes SET status='failed' WHERE id=?").run(cube.id); streamEvent(res, { log: `✗ 「${cube.name}」生成失败:${e.message}\n` }); - streamEvent(res, { task: cube.name, status: "failed", message: e.message }); + streamEvent(res, { task: cube.name, status: "failed", message: `${e.message};失败页面可在「功能与菜单」中单独点「生成」重试` }); } - })); + }); streamEvent(res, { log: "\n▶ 正在打包与校验交付物…\n" }); streamEvent(res, { task: "打包与检查校验", status: "running" }); const zipPath = await createSiteZip(siteId); diff --git a/public/design-doc.html b/public/design-doc.html index 893c0d9..f564c5a 100644 --- a/public/design-doc.html +++ b/public/design-doc.html @@ -283,7 +283,7 @@
  1. 发起:在「生成确认」点「开始生成」→ 前端 POST /api/db/sites/:id/generate-all(携带各 Cube 的名称与内容)。
  2. -
  3. 落库与准备:db-sidecar 先持久化前端传入的 Cube,再以 Promise.all 并行调用各 Cube 的生成(各页相互独立,互不阻塞)。
  4. +
  5. 落库与准备:db-sidecar 先持久化前端传入的 Cube,再以最多 3 个并发的 mapWithConcurrency 调用各 Cube 的生成(各页相互独立,互不阻塞;限制并发以避免资源争抢导致单页超时)。
  6. 调用模型:每页调用 AI 生成服务(后端 runCodebuddy 封装)→ 生成进程以流式 JSON 输出。提示词内含可视化生成 Skill 的 Cube 结构规则(DASHBOARD_SPEC)与站点/样式上下文;DASHBOARD_SPEC 已要求模拟数据精简(时序 ≤16 点、KPI/表格样例 ≤6 行)以缩短输出。
  7. 解析与校验(含代码级自动修复):从流式输出抽取 JSON → fixDashboard 先做代码级自动修复(修复 x+w>24、面板重叠、首面板 Title 定位、KPI/Radar/Line 等 data 字段、缺失 id/gridPos 等)→ 再 validateDashboard 复校;仅当残留问题确无法自动修复时才再次调用模型(最多 2 次模型调用,原 3 次)。
  8. 写回:生成的 JSON 存入 gen_files 并关联 Cube,状态置为 generated,同时保存组合提示词。
  9. @@ -346,6 +346,7 @@
  10. 2026-08-18 新增「AI 智能补全」功能:站点基本属性页「填写建议」下方新增面板,点击「开始补全」后基于站点名称 / 所属领域 / 站点基本情况描述,由 AI 流式分析并自动写入「补充要求」字段;「查看提示词」可查看完整组合提示词(后端 POST /api/db/sites/:id/complete 流式、GET .../complete-prompt 取提示词)。
  11. 2026-08-18 扩展「AI 智能补全」至 Asset 资产设置页:右侧新增与基本属性同款的「填写建议 + AI 智能补全」栏;点击「开始补全」后基于站点名称 / 领域 / 描述 / 补充要求分析并补充设备类型、数量预设与命名规则,追加到用户已填项下方(不改动已有项),资产层级预览随之重算(后端 POST /api/db/sites/:id/complete-assets 流式、GET .../complete-assets-prompt 取提示词)。
  12. 2026-08-18 重构「功能与菜单」页:① MU 标准页面改为树状上下结构、仅保留勾选框、默认全选中;② Cube 扩展页面右侧新增「填写建议 + AI 智能补全」栏,点击「开始补全」后基于站点属性与设备资产层级由 AI 推断并补充 Cube 扩展页面(名称 + 详尽内容),追加到用户已建页面下方(不改动用户内容)(后端 POST /api/db/sites/:id/complete-cubes 流式、GET .../complete-cubes-prompt 取提示词);③ 菜单结构改为只读默认预览:MU 页面在上,所有 Cube 页面归入「综合监控」一级菜单、二级为各 Cube 名称,仅展示无编辑。
  13. +
  14. 2026-08-18 修复整站生成超时:将「生成确认」页全站生成由无上限 Promise.all 并行改为最多 3 个并发(mapWithConcurrency),避免 9 个 Cube 同时抢占 CPU/模型 API 资源导致部分页面 300s 超时失败;超时阈值维持 300s 不变,单页失败不再自动重试,仅提示用户到「功能与菜单」对该页面单独点「生成」重试。
    • -- 2.43.0