Pull requests / #2692
#2692 web: one long-lived stream instead of a poll per second, and a language pack (#2686, #2687)
open · @MrKop-git · 0 comments · View on GitHub
Setup & installServer & APISecurityDocumentation
Description
## Title Issue: Resolves #2687, resolves #2686 ## Summary The web app stopped asking the server once a second and now keeps one long-lived response open instead, and it speaks more than one language: a UTF-8 pack per language under `serve/web/i18n`, Simplified Chinese first. Two issues, one change each: - **#2687 (bug):** the page rewrote its own text on every poll, which fought Chrome's page translation and flipped the UI back to English - once a second on the Monitor. A stream writes only when something actually changed, and nothing at all while nothing does. The page also sets `translate="no"`, so the browser stops offering to translate a page that now translates itself. - **#2686 (feature):** one JSON pack per language, chosen from the browser's own language or from a new switch under About > Settings. **UTF-8 everywhere, never GBK/cp936.** ## What changed - `serve/server.py`: `GET /metrics/stream` and `GET /api/requests/stream` - one `text/event-stream` response each, written to only when what the page draws from changed. `?every=N` (1..60, default 1) sets the server's tick; `?requests=all` keeps the "Show all" behaviour. Both end when the tab closes (the next tick notices the socket) or when the server stops, and both use the existing API-key check. `GET /i18n` lists the packs; `/web/i18n/<lang>.json` serves them as `application/json; charset=utf-8`. No path may leave the folder. - `serve/web/app.js`, `serve/web/monitor.js`: open that stream with `EventSource`. A server without the routes never delivers an event, so the page falls back to its old timer - an older server behaves exactly as it did before. - `serve/web/i18n/en.json`, `serve/web/i18n/zh-CN.json`: 305 keys each, one UTF-8 file per language, with a `meta` (`name`, `dir`). `index.html` carries `data-i18n` keys and `app.js` builds its runtime strings through `t()`. - `serve/web/index.html`, `serve/web/monitor.html`: `translate="no"`. - `serve/test_web_stream.py`: 17 tests - the streams (the event and its payload, the API key, the client hanging up, the server stopping), the packs (valid UTF-8, no BOM, the same key set, served as UTF-8 JSON, no path out of the folder), and the pack logic itself run in node with the DOM stubbed out. - `docs/DETAILS.md`: what the streams and the packs are, and how to add a language. ## What it leaves alone The engine, the OpenAI/Anthropic APIs, the model's answers, the installer and the default path. An English browser on a current server sees the same page it saw before, and a page on a server without `/metrics/stream` keeps polling as it always did. ## Extra Notes **How I checked** - `python3 -m unittest serve.test_web_stream`: 17 passed. - `serve.test_monitor`, `serve.test_runconfig`, `serve.test_security`, `serve.test_server`: 356 tests, the 3 errors are the pre-existing `ModuleNotFoundError: No module named 'regex'` from `tools/strata_tokenizer.py` - they fail on a clean checkout here too, before this change. - `node --check` on `app.js` and `monitor.js`; every touched file decoded as UTF-8 with no BOM. **On the translation itself** The wording is translated, the terms are not, and a test asserts it: **token** stays "token(s)" - never 代币 or 令牌 - and VRAM, PCIe, Prefill, Decode, MTP, KV cache, Top-p, Top-k, seed, GPU, CPU and API key are left as they are, because they are what the user reads in the logs, in the docs and in their own client. **Adding a language later** Drop a `<lang>.json` next to `en.json` with the same keys and a `meta`: `GET /i18n` picks it up and the Settings switch lists it. A key a pack lacks shows as the key, never as a blank, so a pack can lag behind the page. **How the stream was measured** I did not measure bytes on the wire. What I can say from the code: the old path was one `GET /metrics` per second per open tab, each answered with the full payload (~7 KB of JSON with a minute of history per series). The new path is one request per tab, then an event only when the fingerprint of `live`, `hardware`, `totals`, `engine`, `conversation_cache` and the newest request changes - so an idle Monitor, which is most of the time, gets nothing after the first event.
Related on this site
Quick links to related pages.