checkpoint before checking out main
This commit is contained in:
@@ -53,7 +53,10 @@ const ru = {
|
||||
settingsOverrides: 'Настройки генерации пресета',
|
||||
settingsPositiveLoras: 'Positive LoRA',
|
||||
settingsNegativeLoras: 'Negative LoRA',
|
||||
settingsPositiveEmbeddings: 'Positive embeddings',
|
||||
settingsNegativeEmbeddings: 'Negative embeddings',
|
||||
settingsAddLora: 'Добавить LoRA',
|
||||
settingsAddEmbedding: 'Добавить embedding',
|
||||
settingsAvatarPreset: 'Аватар',
|
||||
settingsCustomPreset: 'Свой промпт (размеры)',
|
||||
settingsFullBodyPreset: 'В полный рост',
|
||||
@@ -431,7 +434,10 @@ const en: Messages = {
|
||||
settingsOverrides: 'Preset generation overrides',
|
||||
settingsPositiveLoras: 'Positive LoRA',
|
||||
settingsNegativeLoras: 'Negative LoRA',
|
||||
settingsPositiveEmbeddings: 'Positive embeddings',
|
||||
settingsNegativeEmbeddings: 'Negative embeddings',
|
||||
settingsAddLora: 'Add LoRA',
|
||||
settingsAddEmbedding: 'Add embedding',
|
||||
settingsAvatarPreset: 'Avatar',
|
||||
settingsCustomPreset: 'Custom prompt (size)',
|
||||
settingsFullBodyPreset: 'Full body',
|
||||
|
||||
@@ -498,6 +498,10 @@ export interface SwarmUiKindPreset {
|
||||
width: number;
|
||||
height: number;
|
||||
shotType: string;
|
||||
positiveLoras?: SwarmUiLoraEntry[] | null;
|
||||
negativeLoras?: SwarmUiLoraEntry[] | null;
|
||||
positiveEmbeddings?: SwarmUiLoraEntry[] | null;
|
||||
negativeEmbeddings?: SwarmUiLoraEntry[] | null;
|
||||
}
|
||||
|
||||
export interface SwarmUiLoraEntry {
|
||||
@@ -518,6 +522,8 @@ export interface SwarmUiModelDefinition {
|
||||
negative: string;
|
||||
positiveLoras: SwarmUiLoraEntry[];
|
||||
negativeLoras: SwarmUiLoraEntry[];
|
||||
positiveEmbeddings: SwarmUiLoraEntry[];
|
||||
negativeEmbeddings: SwarmUiLoraEntry[];
|
||||
}
|
||||
|
||||
export interface SwarmUiPresetDefinition {
|
||||
@@ -534,6 +540,8 @@ export interface SwarmUiPresetDefinition {
|
||||
seed?: number | null;
|
||||
positiveLoras?: SwarmUiLoraEntry[] | null;
|
||||
negativeLoras?: SwarmUiLoraEntry[] | null;
|
||||
positiveEmbeddings?: SwarmUiLoraEntry[] | null;
|
||||
negativeEmbeddings?: SwarmUiLoraEntry[] | null;
|
||||
avatar: SwarmUiKindPreset;
|
||||
custom: SwarmUiKindPreset;
|
||||
fullBody: SwarmUiKindPreset;
|
||||
@@ -556,6 +564,7 @@ export interface SwarmUiDiscovery {
|
||||
connected: boolean;
|
||||
models: readonly string[];
|
||||
loras: readonly string[];
|
||||
embeddings: readonly string[];
|
||||
samplers: readonly string[];
|
||||
schedulers: readonly string[];
|
||||
}
|
||||
|
||||
@@ -128,6 +128,8 @@ describe('createSchoolDialog', () => {
|
||||
negative: '',
|
||||
positiveLoras: [],
|
||||
negativeLoras: [],
|
||||
positiveEmbeddings: [],
|
||||
negativeEmbeddings: [],
|
||||
},
|
||||
],
|
||||
presets: [
|
||||
|
||||
@@ -43,6 +43,8 @@ function settings(): SwarmUiSettingsFile {
|
||||
negative: '',
|
||||
positiveLoras: [],
|
||||
negativeLoras: [],
|
||||
positiveEmbeddings: [],
|
||||
negativeEmbeddings: [],
|
||||
},
|
||||
{
|
||||
id: 'other.safetensors',
|
||||
@@ -57,6 +59,8 @@ function settings(): SwarmUiSettingsFile {
|
||||
negative: '',
|
||||
positiveLoras: [],
|
||||
negativeLoras: [],
|
||||
positiveEmbeddings: [],
|
||||
negativeEmbeddings: [],
|
||||
},
|
||||
],
|
||||
presets: [
|
||||
@@ -80,6 +84,7 @@ function discovery(overrides: Partial<SwarmUiDiscovery> = {}): SwarmUiDiscovery
|
||||
connected: true,
|
||||
models: ['template.safetensors', 'not-in-config.safetensors'],
|
||||
loras: [],
|
||||
embeddings: [],
|
||||
samplers: ['euler'],
|
||||
schedulers: ['normal'],
|
||||
...overrides,
|
||||
@@ -135,7 +140,8 @@ describe('swarmUiSettingsDialog', () => {
|
||||
|
||||
expect([...dialog.querySelectorAll('.field__label')].some((node) => node.textContent === t('settingsStyle'))).toBe(true);
|
||||
expect([...dialog.querySelectorAll('.field__label')].some((node) => node.textContent === t('settingsShotType'))).toBe(true);
|
||||
expect(dialog.querySelector('.settings-model')?.textContent).toContain(t('settingsModelDefaults'));
|
||||
expect(dialog.querySelector('.settings-model')?.textContent).toContain(t('settingsPositiveEmbeddings'));
|
||||
expect([...dialog.querySelectorAll('.settings-kind .settings-subtitle')].some((node) => node.textContent === t('settingsPositiveEmbeddings'))).toBe(true);
|
||||
const spoiler = dialog.querySelector('details.settings-overrides');
|
||||
if (!(spoiler instanceof HTMLDetailsElement)) {
|
||||
throw new Error('overrides spoiler is missing');
|
||||
|
||||
@@ -264,8 +264,10 @@ export function swarmUiSettingsDialog(initial?: SwarmUiSettingsFile): Promise<Sw
|
||||
numberField(t('settingsSeed'), model.seed, (value) => {
|
||||
model.seed = value;
|
||||
}),
|
||||
loraSection(t('settingsPositiveLoras'), model.positiveLoras),
|
||||
loraSection(t('settingsNegativeLoras'), model.negativeLoras),
|
||||
loraSection(t('settingsPositiveLoras'), model.positiveLoras, discovery.loras, t('settingsAddLora')),
|
||||
loraSection(t('settingsNegativeLoras'), model.negativeLoras, discovery.loras, t('settingsAddLora')),
|
||||
loraSection(t('settingsPositiveEmbeddings'), model.positiveEmbeddings, discovery.embeddings, t('settingsAddEmbedding')),
|
||||
loraSection(t('settingsNegativeEmbeddings'), model.negativeEmbeddings, discovery.embeddings, t('settingsAddEmbedding')),
|
||||
);
|
||||
return host;
|
||||
}
|
||||
@@ -295,16 +297,33 @@ export function swarmUiSettingsDialog(initial?: SwarmUiSettingsFile): Promise<Sw
|
||||
}),
|
||||
);
|
||||
|
||||
const positiveLoras = preset.positiveLoras ?? [];
|
||||
const negativeLoras = preset.negativeLoras ?? [];
|
||||
preset.positiveLoras = preset.positiveLoras ?? null;
|
||||
const positiveHost = loraSection(t('settingsPositiveLoras'), positiveLoras, () => {
|
||||
preset.positiveLoras = positiveLoras;
|
||||
});
|
||||
const negativeHost = loraSection(t('settingsNegativeLoras'), negativeLoras, () => {
|
||||
preset.negativeLoras = negativeLoras;
|
||||
});
|
||||
body.append(positiveHost, negativeHost);
|
||||
const bindList = (
|
||||
title: string,
|
||||
current: SwarmUiLoraEntry[] | null | undefined,
|
||||
names: readonly string[],
|
||||
addLabel: string,
|
||||
assign: (items: SwarmUiLoraEntry[]) => void,
|
||||
): HTMLElement => {
|
||||
const items = current ?? [];
|
||||
return loraSection(title, items, names, addLabel, () => {
|
||||
assign(items);
|
||||
});
|
||||
};
|
||||
|
||||
body.append(
|
||||
bindList(t('settingsPositiveLoras'), preset.positiveLoras, discovery.loras, t('settingsAddLora'), (items) => {
|
||||
preset.positiveLoras = items;
|
||||
}),
|
||||
bindList(t('settingsNegativeLoras'), preset.negativeLoras, discovery.loras, t('settingsAddLora'), (items) => {
|
||||
preset.negativeLoras = items;
|
||||
}),
|
||||
bindList(t('settingsPositiveEmbeddings'), preset.positiveEmbeddings, discovery.embeddings, t('settingsAddEmbedding'), (items) => {
|
||||
preset.positiveEmbeddings = items;
|
||||
}),
|
||||
bindList(t('settingsNegativeEmbeddings'), preset.negativeEmbeddings, discovery.embeddings, t('settingsAddEmbedding'), (items) => {
|
||||
preset.negativeEmbeddings = items;
|
||||
}),
|
||||
);
|
||||
details.append(body);
|
||||
return details;
|
||||
}
|
||||
@@ -367,32 +386,38 @@ export function swarmUiSettingsDialog(initial?: SwarmUiSettingsFile): Promise<Sw
|
||||
}
|
||||
}
|
||||
|
||||
function loraSection(title: string, loras: SwarmUiLoraEntry[], onMutate?: () => void): HTMLElement {
|
||||
function loraSection(
|
||||
title: string,
|
||||
items: SwarmUiLoraEntry[],
|
||||
names: readonly string[],
|
||||
addLabel: string,
|
||||
onMutate?: () => void,
|
||||
): HTMLElement {
|
||||
const host = el('div', { class: 'settings-loras' });
|
||||
const heading = el('h4', { class: 'settings-subtitle', text: title });
|
||||
const rows = el('div', { class: 'settings-lora-rows' });
|
||||
|
||||
const paintRows = (): void => {
|
||||
rows.replaceChildren();
|
||||
for (const lora of loras) {
|
||||
const nameField = choiceField('', lora.name, discovery.loras, (value) => {
|
||||
lora.name = value;
|
||||
for (const item of items) {
|
||||
const nameField = choiceField('', item.name, names, (value) => {
|
||||
item.name = value;
|
||||
});
|
||||
const weightInput = el('input', { class: 'input', type: 'number', value: String(lora.weight) });
|
||||
const weightInput = el('input', { class: 'input', type: 'number', value: String(item.weight) });
|
||||
weightInput.step = '0.05';
|
||||
weightInput.min = '-4';
|
||||
weightInput.max = '4';
|
||||
weightInput.addEventListener('input', () => {
|
||||
lora.weight = Number(weightInput.value);
|
||||
item.weight = Number(weightInput.value);
|
||||
});
|
||||
const remove = el('button', {
|
||||
class: 'button button--small button--danger',
|
||||
type: 'button',
|
||||
text: '×',
|
||||
onClick: () => {
|
||||
const index = loras.indexOf(lora);
|
||||
const index = items.indexOf(item);
|
||||
if (index >= 0) {
|
||||
loras.splice(index, 1);
|
||||
items.splice(index, 1);
|
||||
}
|
||||
|
||||
paintRows();
|
||||
@@ -406,9 +431,9 @@ export function swarmUiSettingsDialog(initial?: SwarmUiSettingsFile): Promise<Sw
|
||||
const add = el('button', {
|
||||
class: 'button button--small',
|
||||
type: 'button',
|
||||
text: t('settingsAddLora'),
|
||||
text: addLabel,
|
||||
onClick: () => {
|
||||
loras.push({ name: discovery.loras[0] ?? '', weight: 1 });
|
||||
items.push({ name: names[0] ?? '', weight: 1 });
|
||||
onMutate?.();
|
||||
paintRows();
|
||||
},
|
||||
@@ -419,6 +444,10 @@ export function swarmUiSettingsDialog(initial?: SwarmUiSettingsFile): Promise<Sw
|
||||
}
|
||||
|
||||
function kindSection(title: string, preset: SwarmUiPresetDefinition['avatar']): HTMLElement {
|
||||
preset.positiveLoras ??= [];
|
||||
preset.negativeLoras ??= [];
|
||||
preset.positiveEmbeddings ??= [];
|
||||
preset.negativeEmbeddings ??= [];
|
||||
return el(
|
||||
'div',
|
||||
{ class: 'settings-kind' },
|
||||
@@ -432,6 +461,10 @@ export function swarmUiSettingsDialog(initial?: SwarmUiSettingsFile): Promise<Sw
|
||||
textareaField(t('settingsShotType'), preset.shotType, (value) => {
|
||||
preset.shotType = value;
|
||||
}),
|
||||
loraSection(t('settingsPositiveLoras'), preset.positiveLoras, discovery.loras, t('settingsAddLora')),
|
||||
loraSection(t('settingsNegativeLoras'), preset.negativeLoras, discovery.loras, t('settingsAddLora')),
|
||||
loraSection(t('settingsPositiveEmbeddings'), preset.positiveEmbeddings, discovery.embeddings, t('settingsAddEmbedding')),
|
||||
loraSection(t('settingsNegativeEmbeddings'), preset.negativeEmbeddings, discovery.embeddings, t('settingsAddEmbedding')),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user