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

Web UI

中文说明

The stdlib gateway serves this tree at /static/. The default workbench shell is the committed Vite build in dist/ (source in ../../../frontend/). OPENAI4S_WEBUI=legacy serves this directory's frozen index.html + app.js instead. Edits under frontend/ need npm run build (or npm run dev against a running daemon); they are not live on reload. An installed wheel serves its packaged copy. Both shells load external scripts under the app's CSP. The client reads and mutates over REST and follows one WebSocket event stream; canonical session state stays on the server.

Molecule viewers load only the vendored 3Dmol runtime; a missing runtime falls back to text without a CDN request. Ketcher 3.7.0 lives under vendor/ketcher/ and runs in the separate, same-origin /ketcher document, preserving authentication and its first-party API bridge. Only the exact vendored editor document /static/vendor/ketcher/index.html permits unsafe-eval, which its upstream runtime needs; the wrapper, app shell and Artifact policies do not gain that exception. With Stage 9 off or assets absent, that route answers a placeholder. Artifact HTML uses a different trust boundary: executable previews run on a scoped alternate loopback origin, as described below.

Runtime responsibilities

Files

File Responsibility
app.js Frozen escape hatch (OPENAI4S_WEBUI=legacy). Do not add features here; new workbench UI goes in ../../../frontend/.
favicon.js Animates the GIF favicon through WebCodecs when available, pauses in hidden tabs, clamps to 10 fps, and falls back to the static GIF.
favicon_anim_64.gif The packaged favicon source: the frames the animation decodes, and the static fallback icon.
index.html The accessible DOM shell for dashboard, conversation workspace, composer, right dock, dialogs, and settings. It applies the theme before first paint and references the static scripts and styles.
ketcher-page.js The /ketcher host page's script: loads the selected artifact into the vendored editor, and POSTs a new structure version back. External for the same reason as login.js — the shared CSP authorizes only same-origin scripts, so the inline <script> this replaces was refused and the editor never initialized. The artifact id arrives on a data-artifact-id attribute rather than interpolated into executable source.
login.html The team-mode sign-in page (OPENAI4S_TEAM_MODE). Inline styles only; its executable code is external under the shared CSP. Served at /login in both modes; the guard 303s unauthenticated browsers here.
login.js The sign-in page's script: POSTs /api/v1/auth/login, shows the one-sentence failure, and redirects home when already signed in or when team mode is off.
replay.html The read-only replay viewer page (M2-3) — a guest's whole UI, and a member's quick look. Served at /replay behind the login guard; inline styles only, script external for the CSP.
replay.js Fetches GET /api/v1/sessions/{id}/replay (the sanitized web-share view.json, built in place) and renders messages and scientific cells as a plain transcript.
scientific_renderers.js Dependency-free parsers and helpers for sequence/MSA, genome, Molfile/SMILES and LaTeX, plus renderer-descriptor validation. They return plain data and never HTML, so the viewer builds the DOM from the records; a small UMD wrapper lets the Node contract test import the same file. Current table/image/PDF/HTML/text presentation lives in frontend/; the legacy equivalent remains in app.js.
style.css The whole visual system: light/dark tokens (including --text-100/--text-300/--surface-0/--warn), fonts, dashboard and workspace layout, activity and artifact components, dialogs, accessibility, and mobile breakpoints. scripts/check_css_tokens.py requires every var(--x) to be declared.
theme-bootstrap.js Applies the saved light/dark theme while the document head is parsed, before the body paints; externalized so CSP authorization never depends on hashing inline HTML.

Subdirectories

Directory Responsibility
dist/ Committed Vite output of ../../../frontend/. Default SPA shell at / and at workbench deep links; /static/dist/ is a normal tree under this directory either way. Rebuild with npm run build in frontend/ and commit the result with the source; do not edit hashed assets by hand. Every script is an external src= file so this tree stays inside CSP script-src 'self'. OPENAI4S_WEBUI=legacy is the escape hatch that serves index.html instead.
share/ The standalone read-only share viewer (share.html/share.js/share.css), served by the relay tunnel's ShareRouter — separate from the main single-page app, and self-contained rather than a reduced build of it. The shell loads share.js and share.css and nothing else: no WebSocket, no shared state with app.js, and its own small Markdown and CSV renderers instead of scientific_renderers.js. The router's asset allowlist does admit scientific_renderers.js and the vendored 3Dmol so a richer viewer could reach for them, but nothing in the current shell requests either.
vendor/ Vendored third-party assets: the minified 3Dmol runtime, the pinned Ketcher 3.7.0 standalone under ketcher/, and font files. 3Dmol is the only third-party JavaScript app.js injects into its own page, and only when a molecule artifact is opened. If the vendored file does not load, the artifact is rendered as plain text — there is no CDN fallback (app.js, the 3Dmol-min.js script tag). Ketcher never joins the main document: the gateway serves it as the separate /ketcher page the workbench opens in an iframe when Stage 9 is on. Treat these as upstream, byte-sensitive assets; they are excluded from formatting and are not documented file-by-file here.

Verification

Run the offline UI contracts from the repository root:

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

Anything that changes interaction or streaming also needs a real browser: start ./start.sh and drive the actual WebSocket flow. See the server package overview and the Web application guide.