← Về thư mục
📄 / / profiles / r-and-d / raw_evidence / OpenAI4S / openai4s / server / webui / README_zh.md

Web UI(浏览器界面)

English

标准库 Gateway 在 /static/ 下提供这棵树。默认工作台外壳是 dist/ 里提交的 Vite 构建产物(源码在 ../../../frontend/)。OPENAI4S_WEBUI=legacy 改发本目录冻结的 index.html + app.js。frontend/ 里的改动需要 npm run build(或对着正在跑的 daemon 用 npm run dev),刷新页面不会自动生效。安装后的 wheel 提供包内副本。两套外壳都在应用 CSP 下加载外链脚本。客户端通过 REST 读取和写入,并跟随一条 WebSocket 事件流;规范会话状态始终在服务端。

分子查看器只加载自带的 3Dmol;运行时缺失时回退到文本,不向 CDN 请求。Ketcher 3.7.0 位于 vendor/ketcher/,在独立但与应用同源的 /ketcher 文档中运行,保留鉴权及第一方 API 桥接。仅精确的编辑器文档 /static/vendor/ketcher/index.html 放行上游运行时所需的 unsafe-eval;包装页、应用外壳及 Artifact 策略均不增加该例外。Stage 9 关闭或资产缺失时,路由返回占位页。Artifact HTML 使用另一条信任边界:可执行预览位于具有范围限制的另一个 loopback origin,详见下文。

运行时职责

文件

文件 职责
app.js 冻结的逃生舱(OPENAI4S_WEBUI=legacy)。不要在这里加功能;新的工作台 UI 在 ../../../frontend/。
favicon.js 浏览器支持时用 WebCodecs 逐帧播放 GIF favicon,标签页隐藏时暂停,钳制到 10 fps,不支持时回退到静态 GIF。
ketcher-page.js /ketcher 宿主页面的脚本:把选中的 Artifact 载入自带编辑器,并把新的结构版本 POST 回去。外链的理由和 login.js 相同——共享 CSP 只放行同源脚本,它替换掉的那段内联 <script> 会被直接拒绝,编辑器根本初始化不了。Artifact id 通过 data-artifact-id 属性传入,而不是插进可执行源码里。
login.html 团队模式登录页(OPENAI4S_TEAM_MODE)。只用内联样式,可执行代码在共享 CSP 下保持外链。两种模式下都在 /login 提供;守卫把未登录的浏览器 303 到这里。
login.js 登录页脚本:POST /api/v1/auth/login,把失败原因一句话展示出来;已登录或团队模式关闭时直接跳回首页。
replay.html 只读回放查看页(M2-3)——guest 的全部界面,也是成员的快速一瞥。在登录守卫之后的 /replay 提供;只用内联样式,脚本外链以过 CSP。
replay.js 拉取 GET /api/v1/sessions/{id}/replay(现场构建的脱敏 web-share view.json),把消息与科学 cell 渲染成朴素的转录稿。
favicon_anim_64.gif 打包的 favicon 源文件:动画解码的帧来自它,静态回退图标也是它。
index.html Dashboard、对话 Workspace、composer、右侧 dock、dialog 与设置的可访问 DOM 骨架。它在首屏绘制前应用主题,并引用静态脚本与样式。
scientific_renderers.js 零依赖的 sequence/MSA、genome、Molfile/SMILES、LaTeX 解析与辅助函数,外加渲染器描述符校验。它们只产出普通数据、绝不产出 HTML,DOM 由查看器依据这些记录构建;一层薄薄的 UMD 包装让 Node 契约测试能直接导入同一个文件。现行 table/image/PDF/HTML/text 展示在 frontend/ 中;旧版实现保留在 app.js 中。
style.css 整套视觉系统:明暗 token(含 --text-100/--text-300/--surface-0/--warn)、字体、Dashboard/Workspace 布局、Activity 与 Artifact 组件、dialog、可访问性以及移动端断点。scripts/check_css_tokens.py 要求每一处 var(--x) 都有声明。
theme-bootstrap.js 在解析文档 head 时、body 绘制前应用已保存的明暗主题;外链后 CSP 授权不再依赖内联 HTML 的 hash。

子目录

目录 职责
dist/ ../../../frontend/ 提交进来的 Vite 构建产物。默认 SPA 外壳在 / 与工作台深链;/static/dist/ 无论开关都是本目录下的普通静态树。在 frontend/ 里 npm run build 重建,并把产物和源码同一 PR 提交;不要手改带哈希的资源。脚本全部是带 src= 的外链,这棵树仍落在 CSP script-src 'self' 里。OPENAI4S_WEBUI=legacy 是改发 index.html 的逃生舱。
share/ 独立的只读分享查看器(share.html/share.js/share.css),由 relay 隧道的 ShareRouter 提供,与主单页应用分开,而且是自成一体的,不是主应用的裁剪版。它的外壳只加载 share.js 和 share.css,别的一概不加载:没有 WebSocket,不与 app.js 共享任何状态,Markdown 和 CSV 也由它自带的极简渲染器处理,而不是 scientific_renderers.js。ShareRouter 的资产白名单确实放行了 scientific_renderers.js 和自带的 3Dmol,好让更完整的查看器可以取用,但当前这套外壳两者都不请求。
vendor/ 从上游取来的第三方资产:压缩版 3Dmol 运行时、ketcher/ 下钉住的 Ketcher 3.7.0 独立版,以及字体文件。3Dmol 是 app.js 唯一会注入自己页面的第三方 JavaScript,而且只有在打开分子 Artifact 时才注入;自带的那份如果加载不上,Artifact 直接退回纯文本展示,不存在 CDN 回退(见 app.js 里注入 3Dmol-min.js 的那处 script 标签)。Ketcher 从不加入主文档:Gateway 把它作为独立的 /ketcher 页面提供,Stage 9 打开时由 workbench 用 iframe 加载。把它们当作上游的、逐字节敏感的资产:不参与格式化,本 README 也不逐个文件说明。

验证

在仓库根目录运行离线 UI 契约:

uv run pytest tests/test_webui_static_contract.py
node tests/scientific_renderers_smoke.cjs

只要改动涉及交互或流式传输,就必须过一遍真实浏览器:启动 ./start.sh,把真正的 WebSocket 流程跑一遍。另见 Server 包总览与 Web 应用指南。