Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions ideas/native_ui_config_mode_tracking.md

This file was deleted.

2 changes: 1 addition & 1 deletion webui/configs/model_params.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
],

"ace_step": [
{"name": "task_route", "type": "choice", "label": "task_route(操作类型)", "default": "text2music", "choices": ["text2music", "complete", "lego", "extract", "cover", "cover-nofsq", "repaint", "remix"], "info": "cover/remix=换词翻唱,非 text2music 需上传源音频;详见 webui/README.md"},
{"name": "route", "type": "choice", "label": "route(操作类型)", "default": "text2music", "choices": ["text2music", "complete", "lego", "extract", "cover", "cover-nofsq", "repaint", "remix"], "info": "cover/remix=换词翻唱,非 text2music 需上传源音频;详见 webui/README.md"},
{"name": "num_inference_steps", "type": "number", "label": "num_inference_steps", "default": 8, "minimum": 1, "maximum": 20, "step": 1, "precision": 0, "info": "扩散步数(turbo 上限 20);remix 路由不填时默认 16,其他路由默认 8"},
{"name": "shift", "type": "slider", "label": "shift(时间步弯曲)", "default": 3.0, "minimum": 1.0, "maximum": 5.0, "step": 0.5, "info": "原版 turbo 默认 3.0;1.0 会明显劣化 remix 换词咬字"},
{"name": "guidance_scale", "type": "slider", "label": "guidance_scale", "default": 1.0, "minimum": 0.0, "maximum": 5.0, "step": 0.1},
Expand Down
20 changes: 10 additions & 10 deletions webui/native/dist/index.html

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions webui/native/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,11 @@ export async function availableVoices(model = ''): Promise<string[]> {
return response.voices;
}

export async function uploadWav(blob: Blob, filename: string, signal?: AbortSignal): Promise<string> {
export async function uploadWav(blob: Blob, signal?: AbortSignal): Promise<string> {
const response = await jsonRequest<{ path: string }>('/v1/ui/upload', {
method: 'POST',
headers: {
'Content-Type': 'audio/wav',
'X-AudioCPP-Filename': filename
'Content-Type': 'audio/wav'
},
body: blob
}, signal);
Expand Down
58 changes: 45 additions & 13 deletions webui/native/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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'] },
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -1017,7 +1049,7 @@
? 44100
: ['asr', 'vad', 'diar', 'align', 'midi'].includes(selected.task) ? 16000 : undefined;
const wav = await browserDecodeToWav(file, targetSampleRate);
return uploadWav(wav, file.name.replace(/\.[^.]+$/, '') + '.wav', aborter?.signal);
return uploadWav(wav, aborter?.signal);
}

function requestOptions() {
Expand Down Expand Up @@ -1205,7 +1237,7 @@
if (!blob.size) return;
const file = new File([blob], `live-${liveChunkNumber}.webm`, { type: blob.type });
const wav = await browserDecodeToWav(file, 16000);
const audio = await uploadWav(wav, `live-${liveChunkNumber}.wav`);
const audio = await uploadWav(wav);
const result = await transcription({
model: selected.id,
audio,
Expand Down
Loading