Skip to content

fix(webui): LFM2.5-Audio conversation panel follow-ups - #864

Merged
0xShug0 merged 3 commits into
0xShug0:mainfrom
Liquid4All:webui-lfm2-panel-fixes
Oct 10, 2026
Merged

0xShug0 merged 3 commits into
0xShug0:mainfrom
Liquid4All:webui-lfm2-panel-fixes

Conversation

@ykhrustalev

Copy link
Copy Markdown
Contributor

Follow-up to #857. A second look at the LFM2.5-Audio conversation panel found a few small bugs. This fixes them. Only the panel and the page hook from #857 change.

What was wrong

  • Picking another model while the panel loaded one for Run could load the wrong model
  • Leaving the Studio tab during that load could leave the turn stuck at "loading the model"
  • Imported settings that need a server reload were not refused, as they are elsewhere on the page
  • Running a turn on the other checkpoint (JP after EN) wiped the conversation even if that turn failed
  • Picking another model during the upload could send the wrong options
  • Another player could keep playing over a reply streaming in
  • One bad audio chunk failed the whole turn
  • After picking another model, the header still said the old turns would be sent
  • The turn list redrew about 50 times a second while a reply streamed

What changes for users

  • These cases now behave as expected
  • A conversation is kept until a turn on another model actually finishes
  • Starting a reply pauses other players
  • If live playback fails, the turn still finishes and the panel says so

Left for later

  • A custom-named S2S entry still shows the family's ASR settings (the fix is in shared page code)
  • With UI management, picking another model in the few milliseconds while the page unloads one still loads the new pick, as for every model

Testing
On an M3 Ultra with headless Chromium:

  • npm run check and npm run build pass
  • Each bug has a browser test that fails on main's page and passes with this PR
  • feat(webui): LFM2.5-Audio conversation panel for speech-to-speech #857's earlier checks pass again (conversations, offline entries, UI management, Firefox)
  • Over four streamed turns, the turn list redrew 65 times instead of 931
  • Not tested: Safari, a real microphone, CPU and CUDA

The last commit rebuilds the page. It also brings in model spec changes from #858 and #859, which did not rebuild it.

Build and run

cd webui/native && npm ci && npm run build && cd ../..
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DAUDIOCPP_MODEL_SET=custom -DAUDIOCPP_MODELS=lfm2_audio \
  -DAUDIOCPP_BUILD_NATIVE_MODEL_MANAGER=ON -DENGINE_ENABLE_OPENMP=OFF
cmake --build build --target audiocpp_server
./build/bin/audiocpp_server --ui --ui-management --backend metal --threads 8

These are the commands tested on the M3 Ultra; on other machines pick your backend.
Then pick an LFM2.5-Audio S2S entry under Voice Conversion / S2S, record or pick a question, and press Run.

A review of the LFM2.5-Audio conversation panel after it merged found
three things to fix in the page's hook for a panel with requestMode
'panel'.

With UI management, the function that loads the entry for a panel read
the selection again after each wait. Press Run on an S2S entry that is
not loaded, then pick another entry in the Model select while it loads:
the page unloaded the entry it had just loaded and loaded the newly
selected one in streaming mode. The function now gets the entry of the
request. After each wait it checks that this entry is still selected;
if not, it stops with "The model changed while it loaded; press Run
again." instead of loading the other one. The panel had this message
for after the load; it now comes from the page. One short wait is left
as it is: the page's doLoad, which every model's Run uses, reads the
selection again after it unloads another loaded model.

On a server with a config file the panel did not call the page's
ensureLoaded. So after the user imported settings that differ from the
configured model, the panel still ran a turn, where the page refuses
other requests with "The imported model settings require a reload
through the server configuration." The run context's function, now
named ensureLoaded, calls the page's ensureLoaded on such a server, and
the panel calls it on both kinds of server. For an entry that the
server does not list, the panel now shows the page's message too.

The hook was described as general, but it checked the speech-to-speech
inputs itself: that source audio is chosen and that no recording is
running. The panel makes these checks now, from the sourceFile and
sourceRecording props the page already passes to panels. It throws the
error that the context's new warning() makes, and the page shows it as
a warning like its own. The run context no longer carries the question.

The warnings read as before, and nothing changes for the other panels.
Fixes from a review of the conversation panel after it merged. They
are all in the panel's own files.

- The conversation is a Svelte store. It was a module object, and only
  the panel that ran a turn drew it again. With UI management, press
  Run on an entry that is not loaded, open the Models tab and come back
  before the load ends: the panel mounted on the way back kept showing
  "loading the model" after the run bar said "Cancelled.", until the
  next Run. Every mounted panel now sees each change, and the refresh
  calls are gone.
- A Run with another entry, such as JP after EN, cleared the
  conversation before anything was checked. So a turn that failed at
  once lost it: the model did not load, the question did not decode,
  or the user pressed Cancel. The turns now stay until the new turn is
  done, and that turn then starts the new conversation.
- For an S2S entry under an id that is not the catalog's, the panel
  takes the family's ASR options out of the request. It decided this
  from the parameter props after the load and the upload, when they
  can be those of another entry the user selected meanwhile. Then the
  ASR options went out and the server rejected the turn. The options
  are now made when Run is pressed.
- Starting a turn stopped only the live player. A player of an earlier
  turn, or the Result column's, went on under the new reply, and the
  Result column's player did not stop a reply that played live. When
  the reply is to play as it streams in, Run now pauses the page's
  audio and video players, and any player that starts stops the live
  reply.
- A stream event whose audio the live player could not use failed the
  turn, though the result has the whole reply. Live playback now stops
  for that turn and the turn finishes. With live playback on, the
  Runtime log says why, and the panel's note says that live playback
  is not available. The note used to say that the browser cannot play
  the stream.
- With turns of one entry listed and another entry selected, the
  header said they go with the next question, while the note said Run
  starts a new conversation. The header does not count them now, and
  their Leave out and Include buttons are disabled until their entry
  is selected again.
- Each stream event updated the turn list, read its layout and set the
  status line: about 50 times a second in a test on an M3 Ultra. The
  list is now updated when text arrives, when the first audio comes
  and when the turn's state changes. The status line changes with each
  whole second of the reply, as in "Streaming the reply: 12 s".
- Three checks that could not fire are removed: for a stream that ends
  without a result (taskStreamEvents throws then), for a conversation
  reset during a turn (it cannot be while the page is busy), and the
  try around source.stop() (each source is started before it is kept).
Rebuilt from this branch's source with the lockfile (node 24.19.0,
npm 11.17.0):

  cd webui/native
  npm ci
  npm run build

0xShug0#858 and 0xShug0#859 changed the Qwen3 TTS, Breeze TTS and Higgs Audio TTS
model specs without rebuilding the page, so this rebuild also brings
those changes into the page.
@0xShug0
0xShug0 merged commit a3610cb into 0xShug0:main Oct 10, 2026
6 checks passed
@0xShug0

0xShug0 commented Oct 10, 2026

Copy link
Copy Markdown
Owner

@ykhrustalev Thanks! Merged.

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.

2 participants