Skip to content

feat(record): say what a meeting is being heard in, and let it be changed mid-meeting - #12

Merged
meocong merged 1 commit into
masterfrom
feat/align-language-when-recording
Aug 14, 2026
Merged

feat(record): say what a meeting is being heard in, and let it be changed mid-meeting#12
meocong merged 1 commit into
masterfrom
feat/align-language-when-recording

Conversation

@meocong

@meocong meocong commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

A default is right most of the time and wrong exactly when it matters — the call that turned out
to be in English, the standup that switched. Until now the only correction was: stop, open settings,
start again. That costs the part of the meeting where somebody noticed.

model_swap now does what its comment always promised

[→] {"cmd":"model_swap","language":"en"}
[←] {"kind":"info","text":"now listening with whisper-tiny in en"}
{"state":"recording","elapsed_s":9.3,"live_model":"whisper-tiny","language":"en","segments":1}

The decoder is rebuilt under the running session — file, timing, audio archive and everything
already transcribed continue. A failed swap leaves the old pipeline running, because losing a
meeting is the worst possible answer to "change the language". Until today the command answered
cannot load: this binary was built without recognition support, in a build that had it.

The interface says what it is hearing

"Đang nghe bằng Tiếng Việt · gipformer-65m" — on every screen, because a recording survives
navigation, with Đổi beside it. It reads /status, never the browser's own preference: a
session that named no language resolves to the daemon's setting, and a banner reading
localStorage would announce "detecting automatically" while the daemon confidently decoded
Vietnamese. SessionStatus::Recording carries the language for exactly that reason.

Multilingual is now a choice

"Nhiều ngôn ngữ (tự động)" appears whether or not a multilingual model is installed — that is
something a user knows before they own the model — and choosing it downloads what it needs.

Two defects driving it exposed

A second installed model broke recording with nothing in the settings the resolver only handled "exactly one", so adding a model for another language made every recording fail with session needs a live model. It now ranks installed models for the language; with no language, it prefers a multilingual one
The app claimed to be recording after a refusal timer running, button red, nothing being written. A non-transient error now stops the microphone and shows the daemon's own words

Verified

full-flow.mjs asserts it end to end: language mid-meeting: (model's own) → vi, segments 3 → 3, still recording. Plus 1289 Rust tests (3 new), 297 web tests, 15/15 browser suites, clippy
-D warnings, fmt, tsc, eslint.

🤖 Generated with Claude Code

…nged mid-meeting

A default is right most of the time and wrong exactly when it matters. The call that turned out to
be in English, the standup that switched — and until now the only way to correct it was to stop,
open settings and start again, which costs the part of the meeting where somebody noticed.

So `model_swap` finally does what its comment has promised since it was written. It carries an
optional language as well as an optional model, both meaning "leave this as it is", and the daemon
rebuilds the decoder under the running session: the file, the timing, the audio archive and
everything already transcribed continue. A swap that fails leaves the old pipeline running, because
losing a meeting is the worst possible answer to "change the language".

Until today it answered `cannot load: this binary was built without recognition support` — in a
build with recognition support.

The interface gains a line while recording, on every screen, because a recording survives
navigation: *"Đang nghe bằng Tiếng Việt · gipformer-65m"*, with a change control beside it. It reads
`/status`, not the browser's own preference: a session that named no language resolves to the
daemon's setting, and a banner reading `localStorage` would announce "detecting automatically"
while the daemon confidently decoded Vietnamese. `SessionStatus::Recording` carries the language for
exactly that reason.

Multilingual meetings are now a choice rather than a side effect. "Nhiều ngôn ngữ (tự động)" is
offered whether or not a multilingual model is installed — that is something a user knows before
they own the model for it — and choosing it downloads what it needs, like choosing a language does.

Two defects fell out of driving it:

* **Installing a second speech model broke recording.** With nothing named in the settings the
  resolver only handled "exactly one", so adding a model for another language made every recording
  fail with `session needs a live model`. It now ranks the installed models for the language, which
  is the same answer the picker gives; with no language at all it prefers a multilingual model,
  because one that only speaks Vietnamese is the wrong guess for a meeting nobody described.
* **The app claimed to be recording when the daemon had refused.** A non-transient error now stops
  the microphone and clears the recording state, with the daemon's own words in the banner. Before,
  the timer ran and the button stayed red while nothing was being written.

`full-flow.mjs` asserts the change end to end: `(model's own) → vi, segments 3 → 3, still recording`.
@meocong
meocong merged commit bb5c3aa into master Aug 14, 2026
10 checks passed
@meocong
meocong deleted the feat/align-language-when-recording branch August 14, 2026 03:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant