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 Kommentare · Auf GitHub

Setup & installServer & APISecurityDocumentation

Beschreibung

## 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.

Mehr auf der Site

Links zu Install, Modellen, Releases.