Bump Assistent to 0.5.3: live inventory, cards, taste, wanted YAML.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+276
-28
@@ -1126,6 +1126,7 @@
|
|||||||
auto_generate: !!$('sa_auto_generate')?.checked,
|
auto_generate: !!$('sa_auto_generate')?.checked,
|
||||||
persona: $('sa_persona')?.value || localStorage.getItem(LS_PERSONA) || 'neutral',
|
persona: $('sa_persona')?.value || localStorage.getItem(LS_PERSONA) || 'neutral',
|
||||||
model_cards: [],
|
model_cards: [],
|
||||||
|
taste_profile: summarizeTaste(),
|
||||||
...initCtx,
|
...initCtx,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1149,20 +1150,48 @@
|
|||||||
}
|
}
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
|
|
||||||
// Recommendation cards for current checkpoint + selected LoRAs only.
|
// Recommendation cards: checkpoint + selected LoRAs + other has_card entries (capped).
|
||||||
const cardKeys = [];
|
const cardKeys = [];
|
||||||
|
const seenCard = new Set();
|
||||||
|
const addKey = (kind, name) => {
|
||||||
|
if (!kind || !name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = `${kind}:${name}`;
|
||||||
|
if (seenCard.has(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seenCard.add(key);
|
||||||
|
cardKeys.push({ kind, name });
|
||||||
|
};
|
||||||
if (ctx.checkpoint?.name) {
|
if (ctx.checkpoint?.name) {
|
||||||
cardKeys.push({ kind: 'checkpoint', name: ctx.checkpoint.name });
|
addKey('checkpoint', ctx.checkpoint.name);
|
||||||
}
|
}
|
||||||
for (const l of ctx.selected_loras || []) {
|
for (const l of ctx.selected_loras || []) {
|
||||||
if (l?.name) {
|
if (l?.name) {
|
||||||
cardKeys.push({ kind: 'lora', name: l.name });
|
addKey('lora', l.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const l of inv.loras || []) {
|
||||||
|
if (l?.has_card && l?.name) {
|
||||||
|
addKey('lora', l.name);
|
||||||
|
}
|
||||||
|
if (cardKeys.length >= 14) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const c of inv.checkpoints || []) {
|
||||||
|
if (c?.has_card && c?.name) {
|
||||||
|
addKey('checkpoint', c.name);
|
||||||
|
}
|
||||||
|
if (cardKeys.length >= 16) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const k of cardKeys) {
|
for (const k of cardKeys) {
|
||||||
const cached = state.modelCards[`${k.kind}:${k.name}`];
|
const cached = state.modelCards[`${k.kind}:${k.name}`];
|
||||||
if (cached) {
|
if (cached) {
|
||||||
ctx.model_cards.push(cached);
|
ctx.model_cards.push(slimCardForContext(cached));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1197,6 +1226,42 @@
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function slimCardForContext(card) {
|
||||||
|
if (!card || typeof card !== 'object') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const out = {
|
||||||
|
kind: card.kind || null,
|
||||||
|
name: card.name || null,
|
||||||
|
triggers: Array.isArray(card.triggers) ? card.triggers.slice(0, 8) : undefined,
|
||||||
|
weight: card.weight != null ? card.weight : undefined,
|
||||||
|
when: card.when ? String(card.when).slice(0, 160) : undefined,
|
||||||
|
avoid: card.avoid ? String(card.avoid).slice(0, 120) : undefined,
|
||||||
|
prompt_hint: card.prompt_hint ? String(card.prompt_hint).slice(0, 160) : undefined,
|
||||||
|
notes: card.notes ? String(card.notes).slice(0, 200) : undefined,
|
||||||
|
};
|
||||||
|
const clean = {};
|
||||||
|
for (const [k, v] of Object.entries(out)) {
|
||||||
|
if (v != null && v !== '') {
|
||||||
|
clean[k] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function summarizeTaste() {
|
||||||
|
const t = state.taste || {};
|
||||||
|
if (!(t.styles?.length || t.likes?.length || t.avoid?.length || t.notes)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
styles: (t.styles || []).slice(0, 8),
|
||||||
|
likes: (t.likes || []).slice(0, 10),
|
||||||
|
avoid: (t.avoid || []).slice(0, 8),
|
||||||
|
notes: t.notes ? String(t.notes).slice(0, 240) : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function slimInventoryLoras(list, limit) {
|
function slimInventoryLoras(list, limit) {
|
||||||
const selected = new Set();
|
const selected = new Set();
|
||||||
try {
|
try {
|
||||||
@@ -1206,26 +1271,60 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
const rows = (list || []).map((l) => ({
|
const softCap = Math.min(limit || 100, 80);
|
||||||
|
const rows = (list || []).map((l) => {
|
||||||
|
const sel = selected.has(String(l.name || '').toLowerCase());
|
||||||
|
const hasCard = !!l.has_card;
|
||||||
|
const krea = !!l.krea_likely;
|
||||||
|
const blurb = l.blurb || l.usage_hint || null;
|
||||||
|
return {
|
||||||
name: l.name,
|
name: l.name,
|
||||||
title: l.title || l.name,
|
title: l.title || l.name,
|
||||||
trigger_phrase: l.trigger_phrase || null,
|
trigger_phrase: l.trigger_phrase || null,
|
||||||
triggers: Array.isArray(l.triggers) ? l.triggers.slice(0, 8) : undefined,
|
triggers: Array.isArray(l.triggers) ? l.triggers.slice(0, 8) : undefined,
|
||||||
architecture: l.architecture || null,
|
architecture: l.architecture || null,
|
||||||
compat_class: l.compat_class || null,
|
compat_class: l.compat_class || null,
|
||||||
has_card: !!l.has_card,
|
has_card: hasCard,
|
||||||
krea_likely: !!l.krea_likely,
|
krea_likely: krea,
|
||||||
blurb: l.blurb || l.usage_hint || null,
|
blurb,
|
||||||
default_weight: l.default_weight || undefined,
|
default_weight: l.default_weight || undefined,
|
||||||
tags: Array.isArray(l.tags) ? l.tags.slice(0, 6) : undefined,
|
tags: Array.isArray(l.tags) ? l.tags.slice(0, 6) : undefined,
|
||||||
_sel: selected.has(String(l.name || '').toLowerCase()),
|
_score: (sel ? 1000 : 0) + (hasCard ? 200 : 0) + (krea ? 50 : 0) + (blurb ? 10 : 0),
|
||||||
}));
|
};
|
||||||
rows.sort((a, b) => (b._sel - a._sel) || (b.krea_likely - a.krea_likely) || String(a.name).localeCompare(String(b.name)));
|
});
|
||||||
return rows.slice(0, limit).map(({ _sel, ...rest }) => {
|
rows.sort((a, b) => b._score - a._score || String(a.name).localeCompare(String(b.name)));
|
||||||
const out = {};
|
// Full detail for top tier; name+trigger only for the rest within softCap.
|
||||||
for (const [k, v] of Object.entries(rest)) {
|
const fullDetail = 36;
|
||||||
if (v != null && v !== '' && !(Array.isArray(v) && !v.length)) {
|
return rows.slice(0, softCap).map((row, idx) => {
|
||||||
out[k] = v;
|
const out = { name: row.name, title: row.title };
|
||||||
|
if (row.trigger_phrase) {
|
||||||
|
out.trigger_phrase = row.trigger_phrase;
|
||||||
|
}
|
||||||
|
if (row.triggers) {
|
||||||
|
out.triggers = row.triggers;
|
||||||
|
}
|
||||||
|
if (row.krea_likely) {
|
||||||
|
out.krea_likely = true;
|
||||||
|
}
|
||||||
|
if (row.has_card) {
|
||||||
|
out.has_card = true;
|
||||||
|
}
|
||||||
|
const rich = idx < fullDetail || row._score >= 200;
|
||||||
|
if (rich) {
|
||||||
|
if (row.architecture) {
|
||||||
|
out.architecture = row.architecture;
|
||||||
|
}
|
||||||
|
if (row.compat_class) {
|
||||||
|
out.compat_class = row.compat_class;
|
||||||
|
}
|
||||||
|
if (row.blurb) {
|
||||||
|
out.blurb = row.blurb;
|
||||||
|
}
|
||||||
|
if (row.default_weight) {
|
||||||
|
out.default_weight = row.default_weight;
|
||||||
|
}
|
||||||
|
if (row.tags) {
|
||||||
|
out.tags = row.tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@@ -1233,7 +1332,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function slimInventoryCheckpoints(list, limit) {
|
function slimInventoryCheckpoints(list, limit) {
|
||||||
return (list || []).slice(0, limit).map((c) => {
|
const rows = (list || []).slice();
|
||||||
|
rows.sort((a, b) => ((b.krea_likely ? 1 : 0) - (a.krea_likely ? 1 : 0)) || ((b.has_card ? 1 : 0) - (a.has_card ? 1 : 0)) || String(a.name).localeCompare(String(b.name)));
|
||||||
|
return rows.slice(0, limit || 40).map((c) => {
|
||||||
const out = {
|
const out = {
|
||||||
name: c.name,
|
name: c.name,
|
||||||
title: c.title || c.name,
|
title: c.title || c.name,
|
||||||
@@ -1249,6 +1350,77 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadTaste() {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(LS_TASTE);
|
||||||
|
if (!raw) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (parsed && typeof parsed === 'object') {
|
||||||
|
state.taste = {
|
||||||
|
styles: Array.isArray(parsed.styles) ? parsed.styles.slice(0, 12) : [],
|
||||||
|
likes: Array.isArray(parsed.likes) ? parsed.likes.slice(0, 16) : [],
|
||||||
|
avoid: Array.isArray(parsed.avoid) ? parsed.avoid.slice(0, 12) : [],
|
||||||
|
notes: String(parsed.notes || '').slice(0, 400),
|
||||||
|
updated: parsed.updated || 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveTaste() {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(LS_TASTE, JSON.stringify(state.taste || {}));
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushUnique(arr, value, max) {
|
||||||
|
const v = String(value || '').trim();
|
||||||
|
if (!v || v.length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lower = v.toLowerCase();
|
||||||
|
const next = (arr || []).filter((x) => String(x).toLowerCase() !== lower);
|
||||||
|
next.unshift(v.slice(0, 80));
|
||||||
|
return next.slice(0, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTasteFromPatch(patch, userText) {
|
||||||
|
if (!patch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const taste = state.taste || { styles: [], likes: [], avoid: [], notes: '' };
|
||||||
|
if (Array.isArray(patch.loras)) {
|
||||||
|
for (const l of patch.loras) {
|
||||||
|
const name = l?.name || l;
|
||||||
|
if (name) {
|
||||||
|
taste.likes = pushUnique(taste.likes, name, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const aspect = patch.aspect || null;
|
||||||
|
if (aspect) {
|
||||||
|
taste.styles = pushUnique(taste.styles, `aspect ${aspect}`, 12);
|
||||||
|
}
|
||||||
|
if (patch.creativity) {
|
||||||
|
taste.styles = pushUnique(taste.styles, `creativity:${patch.creativity}`, 12);
|
||||||
|
}
|
||||||
|
const ut = String(userText || '').toLowerCase();
|
||||||
|
if (/фото|photo|photoreal|реализм|film grain/.test(ut)) {
|
||||||
|
taste.styles = pushUnique(taste.styles, 'photoreal / film', 12);
|
||||||
|
}
|
||||||
|
if (/аниме|anime|illustration|иллюстр/.test(ut)) {
|
||||||
|
taste.styles = pushUnique(taste.styles, 'illustration / anime', 12);
|
||||||
|
}
|
||||||
|
if (/без\s+3d|не\s+3d|no\s+3d|не\s+render/.test(ut)) {
|
||||||
|
taste.avoid = pushUnique(taste.avoid, '3D render look', 12);
|
||||||
|
}
|
||||||
|
taste.updated = Date.now();
|
||||||
|
state.taste = taste;
|
||||||
|
saveTaste();
|
||||||
|
}
|
||||||
|
|
||||||
function isPatchObject(obj) {
|
function isPatchObject(obj) {
|
||||||
if (!obj || typeof obj !== 'object') {
|
if (!obj || typeof obj !== 'object') {
|
||||||
return false;
|
return false;
|
||||||
@@ -1967,11 +2139,12 @@
|
|||||||
if (btn) {
|
if (btn) {
|
||||||
btn.textContent = 'Downloaded';
|
btn.textContent = 'Downloaded';
|
||||||
}
|
}
|
||||||
refreshInventory(() => {
|
refreshInventory(async () => {
|
||||||
if ($('sa_input')) {
|
await maybeWriteCardAfterDownload({
|
||||||
$('sa_input').value = `LoRA "${payload.name}" is now installed. Enable it with its triggers and improve the prompt.`;
|
kind: 'lora',
|
||||||
}
|
name: payload.name,
|
||||||
sendChat({ fromDownload: true });
|
civitai: card,
|
||||||
|
});
|
||||||
}, { rescan: true });
|
}, { rescan: true });
|
||||||
} else {
|
} else {
|
||||||
setStatus(msg || 'Download failed');
|
setStatus(msg || 'Download failed');
|
||||||
@@ -2008,6 +2181,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function maybeWriteCardAfterDownload({ kind, name, civitai }) {
|
||||||
|
const display = name || civitai?.file_name || civitai?.name || 'model';
|
||||||
|
appendSystemNote(`Downloaded ${display}. Writing a recommendation card…`);
|
||||||
|
setPackValue('catalog_card', { flash: true });
|
||||||
|
const meta = {
|
||||||
|
triggers: civitai?.triggers || [],
|
||||||
|
base_model: civitai?.base_model,
|
||||||
|
civitai_url: civitai?.url || civitai?.civitai_url,
|
||||||
|
version_id: civitai?.version_id || civitai?.modelVersionId,
|
||||||
|
name: display,
|
||||||
|
};
|
||||||
|
if ($('sa_input')) {
|
||||||
|
$('sa_input').value = '';
|
||||||
|
}
|
||||||
|
await sendChat({
|
||||||
|
forcedUserText: `LoRA "${display}" is now installed. Write a recommendation card (JSON) using its triggers/metadata. Then briefly suggest how to enable it in the next generate.`,
|
||||||
|
skipSlash: true,
|
||||||
|
skipAutoPack: true,
|
||||||
|
fromDownload: true,
|
||||||
|
fromCards: true,
|
||||||
|
cardTarget: { kind: kind || 'lora', name: display, meta },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function wantsAutoVision() {
|
function wantsAutoVision() {
|
||||||
return !!$('sa_auto_vision')?.checked;
|
return !!$('sa_auto_vision')?.checked;
|
||||||
}
|
}
|
||||||
@@ -2429,22 +2626,47 @@
|
|||||||
|
|
||||||
async function prefetchActiveModelCards() {
|
async function prefetchActiveModelCards() {
|
||||||
const keys = [];
|
const keys = [];
|
||||||
|
const seen = new Set();
|
||||||
|
const add = (kind, name) => {
|
||||||
|
if (!kind || !name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = `${kind}:${name}`;
|
||||||
|
if (seen.has(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seen.add(key);
|
||||||
|
keys.push({ kind, name });
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
const ck = resolveCurrentCheckpoint();
|
const ck = resolveCurrentCheckpoint();
|
||||||
if (ck?.name) {
|
if (ck?.name) {
|
||||||
keys.push({ kind: 'checkpoint', name: ck.name });
|
add('checkpoint', ck.name);
|
||||||
}
|
}
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
try {
|
try {
|
||||||
if (typeof loraHelper !== 'undefined' && Array.isArray(loraHelper?.selected)) {
|
if (typeof loraHelper !== 'undefined' && Array.isArray(loraHelper?.selected)) {
|
||||||
for (const l of loraHelper.selected) {
|
for (const l of loraHelper.selected) {
|
||||||
const name = l?.name || l;
|
add('lora', l?.name || l);
|
||||||
if (name) {
|
|
||||||
keys.push({ kind: 'lora', name });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
|
for (const l of state.inventory?.loras || []) {
|
||||||
|
if (l?.has_card) {
|
||||||
|
add('lora', l.name);
|
||||||
|
}
|
||||||
|
if (keys.length >= 14) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const c of state.inventory?.checkpoints || []) {
|
||||||
|
if (c?.has_card) {
|
||||||
|
add('checkpoint', c.name);
|
||||||
|
}
|
||||||
|
if (keys.length >= 16) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
await Promise.all(keys.map((k) => prefetchCard(k.kind, k.name)));
|
await Promise.all(keys.map((k) => prefetchCard(k.kind, k.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2689,11 +2911,33 @@
|
|||||||
const { fromAutoCritique, fromVisionHop, fromCards } = opts;
|
const { fromAutoCritique, fromVisionHop, fromCards } = opts;
|
||||||
if (fromCards) {
|
if (fromCards) {
|
||||||
const card = extractCardJson(reply);
|
const card = extractCardJson(reply);
|
||||||
if (card && $('sa_card_json')) {
|
if (card) {
|
||||||
|
if ($('sa_card_json')) {
|
||||||
$('sa_card_json').value = JSON.stringify(card, null, 2);
|
$('sa_card_json').value = JSON.stringify(card, null, 2);
|
||||||
|
}
|
||||||
|
if (opts.fromDownload || opts.cardTarget) {
|
||||||
|
const kind = card.kind || opts.cardTarget?.kind || 'lora';
|
||||||
|
const name = card.name || opts.cardTarget?.name;
|
||||||
|
if (name && typeof genericRequest === 'function') {
|
||||||
|
genericRequest(
|
||||||
|
'AssistentSaveCard',
|
||||||
|
{ kind, name, card, enqueue_wanted: false },
|
||||||
|
(data) => {
|
||||||
|
if (data?.path) {
|
||||||
|
state.modelCards[`${kind}:${name}`] = card;
|
||||||
|
setCardStatus(data.installed ? `Card saved → ${data.path}` : `Card draft → ${data.path}`);
|
||||||
|
setStatus(`Card saved for ${name}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
() => setCardStatus('Card draft ready — Save manually'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
setView('cards');
|
setView('cards');
|
||||||
setCardStatus('Draft from Assistent — review & Save');
|
setCardStatus('Draft from Assistent — review & Save');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { patch } = extractPatch(reply);
|
const { patch } = extractPatch(reply);
|
||||||
@@ -2715,6 +2959,7 @@
|
|||||||
}
|
}
|
||||||
if (patch && $('sa_auto_apply')?.checked) {
|
if (patch && $('sa_auto_apply')?.checked) {
|
||||||
await applyPatch(patch, 'all');
|
await applyPatch(patch, 'all');
|
||||||
|
updateTasteFromPatch(patch, opts.userText || '');
|
||||||
if (!fromAutoCritique) {
|
if (!fromAutoCritique) {
|
||||||
const src = await runGenerateFromPatch(patch);
|
const src = await runGenerateFromPatch(patch);
|
||||||
if (src) {
|
if (src) {
|
||||||
@@ -3018,6 +3263,7 @@
|
|||||||
// (rescans disk when inventory is older than ~20s or after downloads).
|
// (rescans disk when inventory is older than ~20s or after downloads).
|
||||||
setStatus('Refreshing inventory…');
|
setStatus('Refreshing inventory…');
|
||||||
await ensureFreshInventory({ forceRescan: !!opts.fromDownload });
|
await ensureFreshInventory({ forceRescan: !!opts.fromDownload });
|
||||||
|
await prefetchActiveModelCards();
|
||||||
|
|
||||||
if (!opts.fromAutoCritique && !opts.fromDownload && !opts.fromVisionHop) {
|
if (!opts.fromAutoCritique && !opts.fromDownload && !opts.fromVisionHop) {
|
||||||
state.critiqueHopUsed = false;
|
state.critiqueHopUsed = false;
|
||||||
@@ -3104,6 +3350,7 @@
|
|||||||
stopBusyUi('Done');
|
stopBusyUi('Done');
|
||||||
await handleReplySideEffects(reply, civitaiResults, {
|
await handleReplySideEffects(reply, civitaiResults, {
|
||||||
...opts,
|
...opts,
|
||||||
|
userText: text,
|
||||||
attachedSlotIds: visionSlots.map((s) => s.id),
|
attachedSlotIds: visionSlots.map((s) => s.id),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -3350,6 +3597,7 @@
|
|||||||
}
|
}
|
||||||
window.__swarmAssistentWired = true;
|
window.__swarmAssistentWired = true;
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
loadTaste();
|
||||||
setView(state.view || 'chat');
|
setView(state.view || 'chat');
|
||||||
updateGate();
|
updateGate();
|
||||||
ensureBoard();
|
ensureBoard();
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ You are **Swarm Assistent**, a collaborative art director for **Krea 2** image g
|
|||||||
- Architecture: Krea 2 (12B DiT). Not FLUX, not SDXL, not FLUX.1-Krea.
|
- Architecture: Krea 2 (12B DiT). Not FLUX, not SDXL, not FLUX.1-Krea.
|
||||||
- Text encoder: Qwen3-VL 4B. VAE: Qwen Image VAE.
|
- Text encoder: Qwen3-VL 4B. VAE: Qwen Image VAE.
|
||||||
- **Turbo** defaults: steps **8** (min 4), CFG **1** (never CFG 0 — broken output), sigma shift **1.15**, side ~**1024** (128–4096 OK).
|
- **Turbo** defaults: steps **8** (min 4), CFG **1** (never CFG 0 — broken output), sigma shift **1.15**, side ~**1024** (128–4096 OK).
|
||||||
- **RAW / Base:** steps ~20–52, CFG ~4–4.5. Community tip: RAW + turbo LoRA ~0.6 often beats pure Turbo for photoreal — mention only if checkpoint looks RAW; do not invent workflows Swarm cannot run.
|
- **RAW / Base:** steps ~20–52, CFG ~4–4.5. If the live checkpoint name/title looks like **RAW** (not Turbo): prefer RAW settings; if a **turbo LoRA** exists in `available_loras`, suggest weight **~0.6** for photoreal (1.0 ≈ full turbo). Swarm Generate cannot run dual-sampler Comfy graphs — do not invent ExtraArgs; only suggest LoRA weight + steps/CFG the UI can set.
|
||||||
- LoRAs: **only Krea2-trained**. Never suggest FLUX/SDXL LoRAs.
|
- LoRAs: **only Krea2-trained**. Never suggest FLUX/SDXL LoRAs.
|
||||||
|
- `model_cards` in live context (when present) beat generic blurbs — follow `when` / `avoid` / `prompt_hint` / `triggers`.
|
||||||
|
- `taste_profile` is the user's remembered preferences across sessions — bias suggestions toward it unless they ask otherwise.
|
||||||
|
|
||||||
## How to prompt (local Swarm, not krea.ai cloud)
|
## How to prompt (local Swarm, not krea.ai cloud)
|
||||||
|
|
||||||
@@ -52,7 +54,9 @@ A JSON block named "Live SwarmUI context" is attached. Treat it as ground truth
|
|||||||
|
|
||||||
- Use only LoRAs listed in `available_loras` (by exact `name`), or candidates from a Civitai search round.
|
- Use only LoRAs listed in `available_loras` (by exact `name`), or candidates from a Civitai search round.
|
||||||
- Prefer listed `trigger_phrase` / `triggers` — **never invent** trigger words.
|
- Prefer listed `trigger_phrase` / `triggers` — **never invent** trigger words.
|
||||||
|
- When present, use `blurb` / `usage_hint` / `tags` / `has_card` to pick the right LoRA.
|
||||||
- When live context includes `model_cards[]` for the current checkpoint / enabled LoRAs, **trust those cards** (`when`, `avoid`, `prompt_hint`, `notes`, `weight`) over guesses.
|
- When live context includes `model_cards[]` for the current checkpoint / enabled LoRAs, **trust those cards** (`when`, `avoid`, `prompt_hint`, `notes`, `weight`) over guesses.
|
||||||
|
- `taste_profile` (styles / likes / avoid) is remembered across browser sessions — bias toward it unless the user overrides.
|
||||||
- Prefer `krea_likely` / Krea architecture entries; ignore FLUX/SDXL LoRAs even if somehow listed.
|
- Prefer `krea_likely` / Krea architecture entries; ignore FLUX/SDXL LoRAs even if somehow listed.
|
||||||
- `default_weight` is a starting LoRA weight when set.
|
- `default_weight` is a starting LoRA weight when set.
|
||||||
- `available_checkpoints` lists installed checkpoints (with short blurbs when known).
|
- `available_checkpoints` lists installed checkpoints (with short blurbs when known).
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Goal: adjust **generation parameters** for Krea 2 Turbo (or RAW if context says
|
|||||||
## Guidelines
|
## Guidelines
|
||||||
|
|
||||||
- **Turbo:** steps 4–12 (default **8**), CFG **1** (never 0), sigma shift ~**1.15**.
|
- **Turbo:** steps 4–12 (default **8**), CFG **1** (never 0), sigma shift ~**1.15**.
|
||||||
- **RAW/base:** steps 20+, CFG ~4–4.5 — only if checkpoint/context indicates Raw.
|
- **RAW/base:** steps 20–52, CFG ~4–4.5 — only if checkpoint/context indicates Raw. If a turbo-distill LoRA is available, weight **0.6** is the usual photoreal compromise (UI LoRA only — no dual-sampler).
|
||||||
- **Aspect:** prefer patch field `aspect` (`1:1`, `4:5`, `2:3`, `16:9`, `9:16`, `4:3`, `3:2`, `2.35:1`) — UI maps to official 1K sizes. Else set width/height near 1024.
|
- **Aspect:** prefer patch field `aspect` (`1:1`, `4:5`, `2:3`, `16:9`, `9:16`, `4:3`, `3:2`, `2.35:1`) — UI maps to official 1K sizes. Else set width/height near 1024.
|
||||||
- **Batch:** `images` or `batch` (1–4 typical).
|
- **Batch:** `images` or `batch` (1–4 typical).
|
||||||
- **Seed:** `lock_seed: true` to reuse current; `vary: true` or `seed: -1` for a new roll; set numeric `seed` for exact reproducibility.
|
- **Seed:** `lock_seed: true` to reuse current; `vary: true` or `seed: -1` for a new roll; set numeric `seed` for exact reproducibility.
|
||||||
|
|||||||
@@ -78,7 +78,9 @@ Restart / rebuild SwarmUI after clone.
|
|||||||
|
|
||||||
**Cards** subtab: edit/save `{stem}.assistent.json` next to weights; live chat gets cards for the current checkpoint + enabled LoRAs only. Uninstalled models can enqueue `.gpu-rent-wanted-models.yaml` for the next `up`.
|
**Cards** subtab: edit/save `{stem}.assistent.json` next to weights; live chat gets cards for the current checkpoint + enabled LoRAs only. Uninstalled models can enqueue `.gpu-rent-wanted-models.yaml` for the next `up`.
|
||||||
|
|
||||||
Live context (checkpoint, server inventory LoRAs + triggers, `model_cards`, wildcards, current params, persona) is injected every request.
|
Live context (checkpoint, server inventory LoRAs + blurbs/triggers, `model_cards`, `taste_profile`, wildcards, current params, persona) is injected every request. Inventory refreshes each chat turn (disk rescan when stale / after download / `/inventory`). After Confirm download Assistent auto-writes a `.assistent.json` card.
|
||||||
|
|
||||||
|
**Wanted queue:** Cards → Enqueue wanted → `/mnt/swarm_data/.gpu-rent-wanted-models.yaml`. Laptop: `gpu-rent capture wanted` (also on `capture models` / seed `up`).
|
||||||
|
|
||||||
**Cloud-only Krea.ai features** (moodboards UI, Generative Sliders, Creativity Raw/Low/Medium/High) are **not** in Swarm. The assistant emulates them with prompt language + board refs. Optional patch fields `creativity` / `intensity` / `complexity` / `movement` guide the LLM only.
|
**Cloud-only Krea.ai features** (moodboards UI, Generative Sliders, Creativity Raw/Low/Medium/High) are **not** in Swarm. The assistant emulates them with prompt language + board refs. Optional patch fields `creativity` / `intensity` / `complexity` / `movement` guide the LLM only.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user