Add silent generate-on-request and composer Build+Gen button.
When the user explicitly asks to generate, auto-apply the patch and run Generate without the Apply button strip; Собрать + Gen reapplies the last patch (or current SwarmUI prompt) and generates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+74
-7
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Swarm Assistent — Krea 2 collaborative chat (Ollama via Swarm API).
|
||||
* v0.7.2: Slim Exact in prompt; no Exact blob in live ctx; tighter preview filter; critique requires vision+JSON.
|
||||
* v0.7.3: Silent apply+gen when user asks to generate; composer «Собрать + Gen» button.
|
||||
*/
|
||||
(function () {
|
||||
const LS_BASE = 'swarm_assistent_base_url';
|
||||
@@ -102,6 +102,8 @@
|
||||
exact: null,
|
||||
sessionExact: {},
|
||||
lastUserParamIntent: false,
|
||||
lastPatch: null,
|
||||
pendingSilentGen: false,
|
||||
enabledSkills: [],
|
||||
kreaProfiles: { turbo: { steps: 8, cfg: 1, sigma_shift: 1.15 }, raw: { steps: 28, cfg: 4.5 } },
|
||||
preferredEmbed: null,
|
||||
@@ -445,6 +447,28 @@
|
||||
return /\b(steps?|cfg|seed|sigma|размер|aspect|ширин|высот|resolution|batch|турбо|turbo|raw)\b/i.test(String(text || ''));
|
||||
}
|
||||
|
||||
function userAsksGenerate(text) {
|
||||
const t = String(text || '');
|
||||
if (!t.trim()) {
|
||||
return false;
|
||||
}
|
||||
if (/^(gen|generate|go|рисуй|давай|ещё|еще)\s*[!.…]*$/i.test(t.trim())) {
|
||||
return true;
|
||||
}
|
||||
return /\b(сгенерируй|сгенерировать|генерируй|generate|нарисуй|перегенерируй|перерисуй|сделай\s+(картинк|изображен|фото)|run\s+generat|\/gen)\b/i.test(t);
|
||||
}
|
||||
|
||||
function rememberLastPatch(patch) {
|
||||
if (patch && typeof patch === 'object' && !isCardObject(patch)) {
|
||||
state.lastPatch = patch;
|
||||
const btn = $('sa_btn_build_gen');
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.title = 'Применить последний патч Assistent и Generate';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyAspectTableFrom(obj) {
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
return false;
|
||||
@@ -918,13 +942,21 @@
|
||||
});
|
||||
}
|
||||
|
||||
function mountPatchActions(parent, patch) {
|
||||
function mountPatchActions(parent, patch, { silent = false } = {}) {
|
||||
if (!parent || !patch) {
|
||||
return;
|
||||
}
|
||||
rememberLastPatch(patch);
|
||||
retireStalePatchActions();
|
||||
const wrap = parent.classList.contains('sa-patch') ? parent : null;
|
||||
const host = wrap || parent;
|
||||
if (silent) {
|
||||
const note = document.createElement('div');
|
||||
note.className = 'sa-patch-actions sa-patch-silent sa-patch-current';
|
||||
note.textContent = 'Применено автоматически · Generate…';
|
||||
host.appendChild(note);
|
||||
return;
|
||||
}
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'sa-patch-actions sa-patch-current';
|
||||
for (const [label, which] of [
|
||||
@@ -956,6 +988,23 @@
|
||||
syncPatchActionAvailability();
|
||||
}
|
||||
|
||||
async function buildCurrentAndGenerate() {
|
||||
if (state.busy || state.generating || isGenerateUnavailable()) {
|
||||
setStatus('Занято — подожди или нажми Стоп');
|
||||
return;
|
||||
}
|
||||
const patch = state.lastPatch;
|
||||
if (patch) {
|
||||
setStatus('Собираю патч → Generate…');
|
||||
await applyPatch(patch, 'all');
|
||||
await runGenerateFromPatch({ ...patch, actions: ['generate'] }, { force: true });
|
||||
return;
|
||||
}
|
||||
// No Assistent patch yet — generate with whatever is already in SwarmUI.
|
||||
setStatus('Generate с текущим промптом…');
|
||||
await runGenerateFromPatch({ actions: ['generate'] }, { force: true });
|
||||
}
|
||||
|
||||
function renderBoard() {
|
||||
const board = $('sa_board');
|
||||
if (!board) {
|
||||
@@ -2606,12 +2655,14 @@
|
||||
div.textContent = prose || text || '';
|
||||
}
|
||||
if (finalPatch) {
|
||||
rememberLastPatch(finalPatch);
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'sa-patch';
|
||||
const pre = document.createElement('pre');
|
||||
pre.textContent = JSON.stringify(finalPatch, null, 2);
|
||||
wrap.appendChild(pre);
|
||||
mountPatchActions(wrap, finalPatch);
|
||||
const silent = !!(meta && meta.silentPatch);
|
||||
mountPatchActions(wrap, finalPatch, { silent });
|
||||
div.appendChild(wrap);
|
||||
}
|
||||
if (civitaiResults && civitaiResults.length) {
|
||||
@@ -2684,12 +2735,14 @@
|
||||
setAssistantBody(el, prose || fullReply || '');
|
||||
el.querySelectorAll('.sa-patch, .sa-civitai-list').forEach((n) => n.remove());
|
||||
if (patch && !isCardObject(patch) && !(card && !patch.prompt && !patch.actions && !patch.loras)) {
|
||||
rememberLastPatch(patch);
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'sa-patch';
|
||||
const pre = document.createElement('pre');
|
||||
pre.textContent = JSON.stringify(patch, null, 2);
|
||||
wrap.appendChild(pre);
|
||||
mountPatchActions(wrap, patch);
|
||||
const silent = !!(meta && meta.silentPatch) || !!state.pendingSilentGen;
|
||||
mountPatchActions(wrap, patch, { silent });
|
||||
el.appendChild(wrap);
|
||||
} else if (card) {
|
||||
const wrap = document.createElement('div');
|
||||
@@ -4212,6 +4265,9 @@
|
||||
return;
|
||||
}
|
||||
const { patch } = extractPatch(reply);
|
||||
if (patch) {
|
||||
rememberLastPatch(patch);
|
||||
}
|
||||
if (Array.isArray(patch?.actions) && patch.actions.map(String).includes('interrupt')) {
|
||||
doInterruptNow();
|
||||
}
|
||||
@@ -4228,16 +4284,23 @@
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (patch && $('sa_auto_apply')?.checked) {
|
||||
const wantsGen = !!(opts.userWantsGenerate || state.pendingSilentGen
|
||||
|| (Array.isArray(patch?.actions) && patch.actions.map(String).includes('generate')));
|
||||
const doApply = !!(patch && (wantsGen || $('sa_auto_apply')?.checked));
|
||||
if (doApply) {
|
||||
await applyPatch(patch, 'all');
|
||||
updateTasteFromPatch(patch, opts.userText || '');
|
||||
if (!fromAutoCritique) {
|
||||
const src = await runGenerateFromPatch(patch);
|
||||
if (!fromAutoCritique && (wantsGen || $('sa_auto_generate')?.checked)) {
|
||||
const src = await runGenerateFromPatch(
|
||||
{ ...patch, actions: Array.isArray(patch.actions) ? patch.actions : ['generate'] },
|
||||
{ force: wantsGen },
|
||||
);
|
||||
if (src) {
|
||||
await maybeAutoCritique(src);
|
||||
}
|
||||
}
|
||||
}
|
||||
state.pendingSilentGen = false;
|
||||
}
|
||||
|
||||
async function applyQuickPatch(patch, note) {
|
||||
@@ -4502,6 +4565,7 @@
|
||||
}
|
||||
if (!opts.fromAutoCritique && !opts.fromDownload && !opts.fromVisionHop) {
|
||||
state.lastUserParamIntent = userTextMentionsParams(text);
|
||||
state.pendingSilentGen = userAsksGenerate(text);
|
||||
}
|
||||
|
||||
if (!opts.fromAutoCritique && !opts.fromDownload && !opts.fromVisionHop && !opts.skipSlash) {
|
||||
@@ -4599,6 +4663,7 @@
|
||||
const msgMeta = {
|
||||
persona: currentPersonaInfo(),
|
||||
pack,
|
||||
silentPatch: !!state.pendingSilentGen,
|
||||
};
|
||||
state.history.push({ role: 'user', content: text });
|
||||
if (state.pendingPersonaNote) {
|
||||
@@ -4671,6 +4736,7 @@
|
||||
await handleReplySideEffects(reply, civitaiResults, {
|
||||
...opts,
|
||||
userText: text,
|
||||
userWantsGenerate: !!state.pendingSilentGen || userAsksGenerate(text),
|
||||
attachedSlotIds: visionSlots.map((s) => s.id),
|
||||
});
|
||||
};
|
||||
@@ -5020,6 +5086,7 @@
|
||||
$('sa_btn_clear_init')?.addEventListener('click', clearInitAndMask);
|
||||
$('sa_btn_clear_image')?.addEventListener('click', () => clearSlot(state.selectedSlotId));
|
||||
$('sa_btn_send')?.addEventListener('click', () => sendChat());
|
||||
$('sa_btn_build_gen')?.addEventListener('click', () => buildCurrentAndGenerate());
|
||||
$('sa_btn_interrupt')?.addEventListener('click', () => {
|
||||
doInterruptNow();
|
||||
state.busy = false;
|
||||
|
||||
@@ -95,7 +95,7 @@ A JSON block named "Live SwarmUI context" is attached. Treat it as ground truth
|
||||
|
||||
### Actions (auto-safe)
|
||||
|
||||
- `"generate"` — after Apply, start generation.
|
||||
- `"generate"` — after Apply, start generation. When the user explicitly asks to generate, always include this; the UI applies silently (no Apply-button strip).
|
||||
- `"search_civitai"` — Civitai search; user Confirms downloads.
|
||||
- `"interrupt"` — stop generation.
|
||||
- `"memory_upsert"` / `"memory_forget"` — write or delete facts in vector memory.
|
||||
|
||||
@@ -29,5 +29,5 @@ Good: `A fluffy red fox sitting alert in fresh powder snow, ears forward, breath
|
||||
|
||||
- Explain briefly what you changed.
|
||||
- JSON patch with at least `prompt`, and `loras` when relevant.
|
||||
- `actions: ["generate"]` when the user wants a new image.
|
||||
- `actions: ["generate"]` when the user wants a new image — the UI will apply the patch and Generate **without** showing Apply buttons.
|
||||
- `aspect` (or width/height) only if framing should change.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
SwarmUI extension for **collaborative Krea 2** prompting via **Ollama**: chat + board (Generate | Refs tabs), LoRA chips, **persona presets** (`Config/personas/`), **vector memory**, model cards with Civitai fetch, img2img/inpaint, slash commands, auto Generate.
|
||||
|
||||
**Version 0.7.2** — Exact KV (slim in prompt); block `ViewSpecial` model-card previews; critique requires vision + real JSON fence.
|
||||
**Version 0.7.3** — Exact KV; silent apply+Generate when user asks; composer **Собрать + Gen**; block model-card previews; critique needs vision + JSON.
|
||||
|
||||
## Layout
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class SwarmAssistentExtension : Extension
|
||||
ExtensionAuthor = "mrleo1nid";
|
||||
Description = "Collaborative Krea 2 assistant: Ollama chat, persona presets, vector memory, model cards, Generate loop.";
|
||||
License = "MIT";
|
||||
Version = "0.7.2";
|
||||
Version = "0.7.3";
|
||||
Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory"];
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
</div>
|
||||
<div class="sa-composer-actions">
|
||||
<button type="button" class="basic-button sa-primary" id="sa_btn_send">Отправить</button>
|
||||
<button type="button" class="basic-button sa-btn-gen" id="sa_btn_build_gen" title="Применить последний патч Assistent (если есть) и Generate">Собрать + Gen</button>
|
||||
<button type="button" class="basic-button" id="sa_btn_interrupt" title="Прервать генерацию / чат" hidden>Стоп</button>
|
||||
<button type="button" class="basic-button" id="sa_btn_clear">Очистить чат</button>
|
||||
<span class="sa-status" id="sa_status"></span>
|
||||
|
||||
Reference in New Issue
Block a user