From 82feecef066ae65f4bdc17a530ebc3041887b285 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 16 Jun 2026 08:21:26 +0800 Subject: [PATCH] =?UTF-8?q?perf(web):=20=E5=88=87=20task=20=E5=B9=B6?= =?UTF-8?q?=E5=8F=91=E6=8B=89=20meta+messages=20+=20=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=2060=E2=86=9230=20+=20bump=200.12.16?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit selectTask 里 meta 与 messages 原本串行 await,改 Promise.all 并发省一个 RTT; MSG_PAGE 60→30 降首屏传输与 markdown/highlight 同步渲染量。切 task 慢非索引问题 ((task_id, idx) 唯一索引已覆盖主查询),故只优化前端串行与窗口大小。 Co-Authored-By: Claude Opus 4.8 (1M context) --- PROGRESS.md | 5 +++++ core/__init__.py | 2 +- web/static/js/chat.js | 14 ++++++++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index 7e0eb78..66272d2 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -21,6 +21,11 @@ ## 已完成关键能力 +### 2026-06-16 / 切 task 提速:meta+messages 并发拉 + 默认窗口降到 30 + +- 体感诊断:切 task 慢**不是索引问题**——`messages` 的 `UniqueConstraint(task_id, idx)` 在 PG 自带 `(task_id, idx)` 复合索引,主查询 `WHERE task_id=? ORDER BY idx`(app.py:1442)既走索引过滤又免排序;也不是"全量加载",前端早已尾部窗口分页。真正的低垂果实是 `selectTask` 里 meta 与 messages **串行 await**,以及首屏窗口偏大。 +- `web/static/js/chat.js`:`selectTask` 把 `GET /v1/tasks/{id}`(meta)与 `loadMessages`(messages)改 `Promise.all` 并发(两者无依赖、落不同 DOM 区),省一个 RTT;`MSG_PAGE` 60→30,降首屏传输 + markdown/highlight 同步渲染量。bump 0.12.15 → 0.12.16。 + ### 2026-06-15 / plot_pub 吸收 nature-figure 投稿级复合图设计纪律 - 联网调研 `nature-figure` skill(MIT,github.com/Yuan1z0825/nature-skills):双层 manifest 路由 + Python/R 双后端 + 生物医学 gallery。判断不整包移植 —— 与已有 plot_pub 高度重叠、R/单细胞/在体内容跟建材院领域不沾边、多文件结构破坏 zcbot 单 SKILL.md 约定。 diff --git a/core/__init__.py b/core/__init__.py index 3055b52..cba6fd2 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,3 +1,3 @@ # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # 改版本只动这一行。 -__version__ = "0.12.15" +__version__ = "0.12.16" diff --git a/web/static/js/chat.js b/web/static/js/chat.js index e4df2f4..7c845ee 100644 --- a/web/static/js/chat.js +++ b/web/static/js/chat.js @@ -241,10 +241,15 @@ export async function selectTask(tid) { $("chat-stream").innerHTML = `
加载中…
`; renderTaskProgressDock([]); try { - const meta = await api("GET", "/v1/tasks/" + tid); + // meta 与 messages 无依赖,并发拉省一个 RTT(切 task 体感更跟手)。 + // loadMessages 内部读 state.taskId(上方已置),不依赖 meta;两者落在 + // 不同 DOM 区(chat-meta / chat-stream),谁先返回先渲染,互不干扰。 + const [meta] = await Promise.all([ + api("GET", "/v1/tasks/" + tid), + loadMessages(), + ]); state.taskMeta = meta; renderChatMeta(); - await loadMessages(); if (meta.run_status === "running" || meta.run_status === "cancelling") { ensureRunningTaskSubscribed(tid, `/v1/tasks/${tid}/events`); } else { @@ -425,8 +430,9 @@ async function onChangeModel(ev) { } // 切 task 默认只拉最近一批(尾部窗口);更早的靠向上滚动按需补。 -// 60 而非 50 留余量:system/task_progress 等被 render 跳过的行也算在窗口里。 -const MSG_PAGE = 60; +// 30:首屏只需铺满一两屏可见消息,降低传输 + markdown/highlight 同步渲染量, +// 切换更跟手;system/task_progress 等被 render 跳过的行也算在这窗口里,留了余量。 +const MSG_PAGE = 30; async function loadMessages() { const data = await api("GET", `/v1/tasks/${state.taskId}/messages?limit=${MSG_PAGE}`);