From fb5e68d9e73b9a63c207eb67d3977080430483c6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 1 Jun 2026 13:46:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(sandbox):=20=E8=A3=85=20CJK=20=E5=AD=97?= =?UTF-8?q?=E4=BD=93=E4=BF=AE=20matplotlib=20/=20mermaid=20=E5=87=BA?= =?UTF-8?q?=E5=9B=BE=E4=B8=AD=E6=96=87=E6=96=B9=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sandbox 镜像基于 python:3.12-slim 一个中文字体都没装,matplotlib / mermaid(chromium)/ render_icon 出的 PNG 中文全是豆腐块。 - Dockerfile: apt 装 fonts-noto-cjk + fonts-wqy-microhei + fontconfig,fc-cache 刷索引 - style.py: 候选首位加 "Noto Sans CJK SC",matplotlib 优先用 Noto - PROGRESS / RUN 故障表同步 改了 Dockerfile 必须重 build 镜像 + 清旧容器才生效。 Co-Authored-By: Claude Opus 4.8 (1M context) --- PROGRESS.md | 1 + RUN.md | 1 + deploy/sandbox/Dockerfile | 12 ++++++++++++ skills/plot_pub/style.py | 3 ++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/PROGRESS.md b/PROGRESS.md index f122ff7..383a1bf 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -23,6 +23,7 @@ ### 2026-06-01 +- **sandbox 镜像加中文字体,修 matplotlib / mermaid 出图中文方块**:用户报绘图(mermaid + matplotlib)出的 PNG 里中文全是豆腐块 □。**根因 = `deploy/sandbox/Dockerfile` 从 `python:3.12-slim` 起一个 CJK 字体都没装**:matplotlib `skills/plot_pub/style.py::_find_chinese_font()` 扫候选无果退回 Arial/DejaVu;mermaid 经 mmdc→chromium 渲染,chromium 经 fontconfig 也找不到中文字形;`skills/ppt/scripts/render_icon.py` 引用的 `wqy-microhei.ttc` / `NotoSansCJK-Regular.ttc` 路径根本不存在。三处同一病根。**改法**:① Dockerfile chromium 块后加一层 `apt-get install fonts-noto-cjk fonts-wqy-microhei fontconfig && fc-cache -f`(Noto 出版级 +~330MB,wqy 兜底 +~5MB 且匹配 style.py 现有候选 / render_icon 引用路径);② `style.py` 候选清单首位加 `"Noto Sans CJK SC"` 让 matplotlib 优先用 Noto。fontconfig 刷缓存供 chromium 选字;matplotlib 走自家 font_manager 扫 `/usr/share/fonts` 运行时首用自动建缓存,无需额外处理。**否决**仅装 wqy(体积小但黑体不如 Noto 精致,出版图略糙)/ 仅装 Noto(render_icon 第一候选 wqy.ttc 落空走 fallback OK 但不够干净)。**纯镜像 + 配置改,DESIGN 不动**(无架构 / 取舍 / schema 变化);`RUN.md` 故障表加一行(中文方块 → 重 build 镜像 + 清旧容器 + `fc-list :lang=zh` 验证)。**生效**:改了 Dockerfile 必须 `docker build` 重建 + `docker rm -f` 清旧容器 + restart web,旧容器仍跑老镜像不会自动更新。 - **documents / Materials Project secret-bearing 能力改 host-side tools,key 不进 sandbox**:新增 `tools/documents.py` 三工具(`document_list_kb` / `document_search` / `document_download`)和 `tools/materials_project.py` 三工具(`mp_search_summary` / `mp_get_structure` / `mp_get_entries`),`core/agent_builder.py` 仅在宿主 env `DOCUMENT_SEARCH_API_KEY` / `MP_API_KEY` 存在时注册。`document_download` / `mp_get_structure` / `mp_get_entries` 绑定当前 task_dir 写文件,模型不能传 working_dir;`document_search` 默认截断 `md_content`,避免整篇论文进上下文。同步更新 `DESIGN.md` secret-bearing domain tools 规则、`RUN.md` env / 故障兜底、`SKILL_LIST.md`、`skills/documents/SKILL.md`、`skills/pymatgen/SKILL.md`;旧 `run_python` helper 不再是带 key API 主路径。测试 `tests/test_secret_host_tools.py` 覆盖 documents search 截断、download 固定 task_dir、MP tool 不泄露 host key。 - **删 `skills/pymatgen/materials.py::mp_rester()` + `scripts/smoke_scientific_skills.py` 改走 host tool**:`mp_rester` 是 sandbox 内读 `MP_API_KEY` 的旧入口,host tool 化后多余且违背"key 不进 sandbox",直接删(连带清 `import os` / `contextlib.contextmanager`,只留 `CEMENT_PHASES` / `lookup_phase`);smoke A6 / step D 改用 `MaterialsProjectSearchSummaryTool`。**实测闭环**:初次 step D 真连 `api.materialsproject.org` 返 **403**(工具行为正确,403 干净透传成 `[Error]` 不崩),定位为 `.env` legacy 旧版 key 在新版 `mp-api` 失效;换 next-gen materialsproject.org dashboard 长 key 后**复测通过**(查 Ca3SiO5 返 3 条 `mp-xxxx` + `energy_above_hull`,~5s),MP host 工具端到端联网通路确认可用。documents 工具未联网实测(无现成可验证调用),逻辑同 web_search 形态。 diff --git a/RUN.md b/RUN.md index 6a5b785..d739aa0 100644 --- a/RUN.md +++ b/RUN.md @@ -614,6 +614,7 @@ sudo xfs_quota -x -c "limit -p bhard=10g zcbot_" /opt | `/v1/*` 全返 401 `missing Authorization: Bearer` | 没拿 token 或没带 header。先 login 拿 token,curl 加 `-H "Authorization: Bearer $TOKEN"` | | `/v1/*` 返 401 `token expired` | JWT 默 7d TTL 到期,重 login。要更长改 `ZCBOT_JWT_TTL_SECONDS` env | | dev.html SSE 收不到流(消息发出去 UI 没动) | EventSource 不支持 header,dev.html 走 `fetch + ReadableStream`。devtools Network 看 POST /messages 是否 202 + events_url GET 是否 200 + Content-Type 是 text/event-stream;401 → token 过期,logout 重 login | +| matplotlib / mermaid 出的 PNG 里中文全是方块(豆腐块 □) | sandbox 镜像缺中文字体。Dockerfile 已加 `fonts-noto-cjk fonts-wqy-microhei` + `fc-cache`,但**改了 Dockerfile 必须重 build 镜像 + 清旧容器**才生效(旧容器仍跑老镜像):`docker build -t zcbot-sandbox:latest -f deploy/sandbox/Dockerfile --build-arg HOST_UID=$(id -u) --build-arg HOST_GID=$(id -g) .` → `docker rm -f $(docker ps -aq -f label=zcbot.product=sandbox)` → `systemctl restart zcbot`。验证:`docker run --rm zcbot-sandbox:latest fc-list :lang=zh` 应列出 Noto/WenQuanYi | | dev.html 显示 "load failed" 立刻回登录页 | token 过期或 JWT_SECRET 服务端变了。已自动跳登录页,按上次 tab 重登 | | dev.html 顶栏出现"连接断开,重连中…(N/3)" | SSE 流被切(`--reload` 重启 / nginx 切换 / 网络抖)。客户端自动重连,1s/2s/4s 退避;新进程已 reaper 标 error 则立即收 done + 卡片末尾"请重发"提示;若服务端还活着会继续看后续 delta(断开期间的丢失,broker 不持久化) | diff --git a/deploy/sandbox/Dockerfile b/deploy/sandbox/Dockerfile index dd8ac7e..36cf068 100644 --- a/deploy/sandbox/Dockerfile +++ b/deploy/sandbox/Dockerfile @@ -75,6 +75,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ chromium nodejs npm \ && rm -rf /var/lib/apt/lists/* +# 中文字体 ── 不装则 matplotlib / mermaid(chromium) / render_icon 出的 PNG 里 +# 中文全是方块(豆腐块 □)。装两套: +# - fonts-noto-cjk: 出版级字形,matplotlib 出版图 / mermaid 节点首选(+~330MB) +# - fonts-wqy-microhei: 兜底,匹配 style.py 候选 'WenQuanYi Micro Hei' +# + render_icon.py 引用的 wqy-microhei.ttc 路径(+~5MB) +# fc-cache 刷 fontconfig 索引 ── chromium 经 fontconfig 选字必需;matplotlib 走自家 +# font_manager 扫 /usr/share/fonts,运行时首次用图自动建缓存,无需在此处理。 +RUN apt-get update && apt-get install -y --no-install-recommends \ + fonts-noto-cjk fonts-wqy-microhei fontconfig \ + && fc-cache -f \ + && rm -rf /var/lib/apt/lists/* + # npm 源可配(同 pip 一样,境内访问 registry.npmjs.org 慢): # --build-arg NPM_REGISTRY=https://mirrors.cloud.tencent.com/npm/ # 腾讯云 # --build-arg NPM_REGISTRY=https://registry.npmmirror.com/ # 阿里 diff --git a/skills/plot_pub/style.py b/skills/plot_pub/style.py index 6a0c75a..aa05d88 100644 --- a/skills/plot_pub/style.py +++ b/skills/plot_pub/style.py @@ -14,9 +14,10 @@ from matplotlib import font_manager # 中文字体候选,按平台优先级排 _CHINESE_FONTS = [ + "Noto Sans CJK SC", # sandbox 容器首选(fonts-noto-cjk),出版级字形 "SimHei", # Windows 黑体 "Microsoft YaHei", # Windows 雅黑 - "WenQuanYi Micro Hei", # Linux + "WenQuanYi Micro Hei", # Linux / 容器兜底(fonts-wqy-microhei) "Heiti TC", # macOS "Arial Unicode MS", # macOS 兜底 ]