From a5b0030896fe166f8d4186939addafb99bde7b08 Mon Sep 17 00:00:00 2001
From: 0xShug0 <231717474+0xShug0@users.noreply.github.com>
Date: Sat, 15 Aug 2026 10:50:28 -0400
Subject: [PATCH 1/2] Remove local ideas notes
---
ideas/native_ui_config_mode_tracking.md | 28 -------------------------
1 file changed, 28 deletions(-)
delete mode 100644 ideas/native_ui_config_mode_tracking.md
diff --git a/ideas/native_ui_config_mode_tracking.md b/ideas/native_ui_config_mode_tracking.md
deleted file mode 100644
index e793f6b7..00000000
--- a/ideas/native_ui_config_mode_tracking.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Native UI Config Mode Tracking
-
-Issue: https://github.com/0xShug0/audio.cpp/issues/234
-
-This note tracks native UI gaps seen when `audiocpp_server` is launched with a
-server config but without `--ui-management`.
-
-## Bugs
-
-- The Studio model picker is built from the embedded model catalog, not from the
- configured `/v1/models` response. In config mode this exposes models that the
- server was not configured to serve.
-- The UI uses catalog IDs as request model IDs. Configured server model IDs are
- deployment-local, so a resident configured model may not be found if its ID
- differs from the catalog ID.
-- Management-only endpoints such as path inspection are correctly forbidden
- when `ui_management=false`, but the UI still probes them and presents unclear
- state.
-- Package choice defaults are precision-centric. This can hide installed BF16
- packages behind a Q8 default and cannot represent multi-axis variants such as
- ACE-Step base vs turbo.
-
-## Intended Direction
-
-- Add a config-mode UI path where selectable models come from `/v1/models`.
-- Keep catalog/package-management behavior behind `--ui-management`.
-- Make loaded/resident state use the actual server model ID.
-- Represent package variants without assuming precision is the only choice axis.
From b5760f79dec7e2fedc433f2ca16574c8b66e4676 Mon Sep 17 00:00:00 2001
From: 0xShug0 <231717474+0xShug0@users.noreply.github.com>
Date: Sat, 15 Aug 2026 11:00:09 -0400
Subject: [PATCH 2/2] Fix native UI loaded model display
---
webui/native/dist/index.html | 20 +++++------
webui/native/src/routes/+page.svelte | 54 ++++++++++++++++++++++------
2 files changed, 53 insertions(+), 21 deletions(-)
diff --git a/webui/native/dist/index.html b/webui/native/dist/index.html
index dcbb7910..89091cdb 100644
--- a/webui/native/dist/index.html
+++ b/webui/native/dist/index.html
@@ -13,20 +13,20 @@
diff --git a/webui/native/src/routes/+page.svelte b/webui/native/src/routes/+page.svelte
index 9394325e..03958046 100644
--- a/webui/native/src/routes/+page.svelte
+++ b/webui/native/src/routes/+page.svelte
@@ -183,10 +183,6 @@
}
}
- function loadedModelName(model: LoadedModel) {
- return catalog.find((entry) => entry.id === model.id)?.display_name || model.id;
- }
-
const workflowTabs = [
{ id: 'tts', label: 'Text to speech', filterLabel: 'TTS', tasks: ['tts', 'clon'] },
{ id: 'asr', label: 'ASR / Transcription', filterLabel: 'ASR', tasks: ['asr'] },
@@ -215,13 +211,53 @@
seed_vc: 'Seed-VC'
};
+ function pathVariantLabel(path: string) {
+ const normalized = path.replace(/\\/g, '/');
+ const filename = normalized.split('/').filter(Boolean).pop() || '';
+ const match = filename.match(/(?:^|[-_])(\d+(?:\.\d+)?[bm])(?:[-_]|$)/i);
+ return match ? match[1].toUpperCase() : '';
+ }
+
+ function catalogPathMatches(expectedPath: string, actualPath: string) {
+ const actual = comparablePath(actualPath);
+ const expected = comparablePath(resolveCatalogPath(expectedPath));
+ if (actual === expected) return true;
+ const relative = comparablePath(expectedPath).replace(/^models\//, '');
+ return actual === relative || actual.endsWith(`/${relative}`);
+ }
+
+ function catalogEntryMatchesLoadedModel(entry: CatalogEntry, model: LoadedModel) {
+ if (entry.family !== model.family || entry.task !== model.task) return false;
+ if (catalogPathMatches(entry.path, model.path)) return true;
+ return Boolean((entry.install_packages || []).some((choice) =>
+ catalogPathMatches(choice.path, model.path)));
+ }
+
+ function loadedCatalogEntry(model: LoadedModel) {
+ const exact = catalog.find((entry) => entry.id === model.id);
+ if (exact && catalogEntryMatchesLoadedModel(exact, model)) return exact;
+ return catalog.find((entry) => catalogEntryMatchesLoadedModel(entry, model));
+ }
+
+ function inferredLoadedModelName(model: LoadedModel, base?: CatalogEntry) {
+ const variant = pathVariantLabel(model.path);
+ const familyName = familyLabels[model.family] || base?.display_name || model.family;
+ return variant && !familyName.toLowerCase().includes(variant.toLowerCase())
+ ? `${familyName} ${variant}`
+ : familyName;
+ }
+
+ function loadedModelName(model: LoadedModel) {
+ return loadedCatalogEntry(model)?.display_name || inferredLoadedModelName(model);
+ }
+
function compareModelNames(left: string, right: string) {
return left.localeCompare(right, 'en', { sensitivity: 'base', numeric: true });
}
function configuredCatalogEntries() {
return loadedModels.map((model) => {
- const exact = catalog.find((entry) => entry.id === model.id);
+ const exact = loadedCatalogEntry(model);
const familyMatch = catalog.find((entry) =>
entry.family === model.family && entry.task === model.task);
const base = exact || familyMatch;
@@ -235,7 +271,7 @@
mode: model.mode
}),
id: model.id,
- display_name: exact ? exact.display_name : base ? `${base.display_name} (${model.id})` : model.id,
+ display_name: exact ? exact.display_name : inferredLoadedModelName(model, base),
display_name_en: exact ? exact.display_name_en : base?.display_name_en,
family: model.family,
path: model.path,
@@ -353,11 +389,7 @@
}
function packagePathMatches(choice: InstallPackageChoice, path: string) {
- const actual = comparablePath(path);
- const expected = comparablePath(resolveCatalogPath(choice.path));
- if (actual === expected) return true;
- const relative = comparablePath(choice.path).replace(/^models\//, '');
- return actual === relative || actual.endsWith(`/${relative}`);
+ return catalogPathMatches(choice.path, path);
}
function residentModel(entry: CatalogEntry, models = loadedModels) {