Fix model-card previews leaking into Generate and vision.
Treat ViewSpecial/Models/*.preview URLs as non-gens, scrub them from the board, and never attach them to chat/look_at/snapshot. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+62
-13
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Swarm Assistent — Krea 2 collaborative chat (Ollama via Swarm API).
|
* Swarm Assistent — Krea 2 collaborative chat (Ollama via Swarm API).
|
||||||
* v0.7.0: Config presets, persona folders, exact KV + vector memory, chat|memory model roles.
|
* v0.7.1: Exact KV memory; block SwarmUI ViewSpecial/model-card previews from Generate+vision.
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
const LS_BASE = 'swarm_assistent_base_url';
|
const LS_BASE = 'swarm_assistent_base_url';
|
||||||
@@ -667,7 +667,7 @@
|
|||||||
return state.slots.filter((s) => s.attach && s.src);
|
return state.slots.filter((s) => s.attach && s.src);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSlotSrc(id, src, { select = true, attach = null, note = null, switchTab = false } = {}) {
|
function setSlotSrc(id, src, { select = true, attach = null, note = null, switchTab = false, allowPreview = false } = {}) {
|
||||||
const slot = slotById(id);
|
const slot = slotById(id);
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
return false;
|
return false;
|
||||||
@@ -676,6 +676,10 @@
|
|||||||
if (cleaned && cleaned.startsWith('#')) {
|
if (cleaned && cleaned.startsWith('#')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (cleaned && !allowPreview && looksLikeModelPreview(cleaned)) {
|
||||||
|
setStatus('Пропуск превью модели (нужна реальная генерация)');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
slot.src = cleaned || null;
|
slot.src = cleaned || null;
|
||||||
if (attach != null) {
|
if (attach != null) {
|
||||||
slot.attach = !!attach;
|
slot.attach = !!attach;
|
||||||
@@ -745,9 +749,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function snapshotGenerateToRef() {
|
function snapshotGenerateToRef() {
|
||||||
const src = generateSlot()?.src || findCurrentGenerateSrc({ allowPreview: true });
|
// Never promote checkpoint/LoRA card previews into Refs.
|
||||||
|
const src = generateSlot()?.src && !looksLikeModelPreview(generateSlot().src)
|
||||||
|
? generateSlot().src
|
||||||
|
: findCurrentGenerateSrc({ allowPreview: false });
|
||||||
if (!src) {
|
if (!src) {
|
||||||
setStatus('Нет текущего кадра Generate');
|
setStatus('Нет текущего кадра Generate (превью модели не считается)');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const empty = refSlots().find((s) => !s.src);
|
const empty = refSlots().find((s) => !s.src);
|
||||||
@@ -1120,11 +1127,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function syncGenerateSlot() {
|
function syncGenerateSlot() {
|
||||||
const src = findCurrentGenerateSrc();
|
|
||||||
const slot = generateSlot();
|
const slot = generateSlot();
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Drop checkpoint/LoRA card previews that slipped into the Generate pane.
|
||||||
|
if (scrubPreviewFromGenerateSlot()) {
|
||||||
|
renderBoard();
|
||||||
|
}
|
||||||
|
const src = findCurrentGenerateSrc();
|
||||||
if (src && src !== slot.src) {
|
if (src && src !== slot.src) {
|
||||||
slot.src = src;
|
slot.src = src;
|
||||||
const img = document.querySelector('.sa-slot-gen img');
|
const img = document.querySelector('.sa-slot-gen img');
|
||||||
@@ -1140,6 +1151,17 @@
|
|||||||
empty.hidden = true;
|
empty.hidden = true;
|
||||||
}
|
}
|
||||||
frame?.classList.add('sa-has-image');
|
frame?.classList.add('sa-has-image');
|
||||||
|
} else if (!src && !slot.src) {
|
||||||
|
const empty = document.querySelector('.sa-slot-gen .sa-image-empty');
|
||||||
|
const frame = document.querySelector('.sa-slot-gen');
|
||||||
|
const img = document.querySelector('.sa-slot-gen img');
|
||||||
|
if (img) {
|
||||||
|
img.remove();
|
||||||
|
}
|
||||||
|
if (empty) {
|
||||||
|
empty.hidden = false;
|
||||||
|
}
|
||||||
|
frame?.classList.remove('sa-has-image', 'sa-attached');
|
||||||
}
|
}
|
||||||
syncGenerateBusy();
|
syncGenerateBusy();
|
||||||
syncPatchActionAvailability();
|
syncPatchActionAvailability();
|
||||||
@@ -2824,9 +2846,17 @@
|
|||||||
if (!s) {
|
if (!s) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return s.includes('.preview.')
|
// SwarmUI checkpoint/LoRA cards: ViewSpecial/*, View/Models/*, *.preview.*, PLACEHOLDER.
|
||||||
|
if (s.includes('.preview.')
|
||||||
|| s.includes('placeholder')
|
|| s.includes('placeholder')
|
||||||
|| /\/models\//i.test(s);
|
|| s.includes('/viewspecial/')
|
||||||
|
|| s.includes('viewspecial/')
|
||||||
|
|| s.includes('/models/')
|
||||||
|
|| s.includes('view/models/')
|
||||||
|
|| /[?&](?:path|file)=[^&]*\.preview\./i.test(s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findCurrentGenerateSrc({ allowPreview = false } = {}) {
|
function findCurrentGenerateSrc({ allowPreview = false } = {}) {
|
||||||
@@ -2837,7 +2867,7 @@
|
|||||||
|| document.querySelector('.current-image img')
|
|| document.querySelector('.current-image img')
|
||||||
|| document.querySelector('#current_image_batch img');
|
|| document.querySelector('#current_image_batch img');
|
||||||
if (cur) {
|
if (cur) {
|
||||||
src = cur.dataset?.src || cur.src || null;
|
src = cur.dataset?.src || cur.getAttribute?.('data-src') || cur.src || null;
|
||||||
}
|
}
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
if (!src) {
|
if (!src) {
|
||||||
@@ -2850,20 +2880,38 @@
|
|||||||
if (!src) {
|
if (!src) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// Strip cache-busters for classification, keep original for display when accepted.
|
||||||
if (!allowPreview && looksLikeModelPreview(src)) {
|
if (!allowPreview && looksLikeModelPreview(src)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scrubPreviewFromGenerateSlot() {
|
||||||
|
const slot = generateSlot();
|
||||||
|
if (!slot?.src) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!looksLikeModelPreview(slot.src)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
slot.src = null;
|
||||||
|
slot.attach = false;
|
||||||
|
syncLastImageAlias();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function refreshImagePreview() {
|
function refreshImagePreview() {
|
||||||
|
scrubPreviewFromGenerateSlot();
|
||||||
if (wantsAutoVision()) {
|
if (wantsAutoVision()) {
|
||||||
const gen = generateSlot();
|
const gen = generateSlot();
|
||||||
if (gen) {
|
if (gen) {
|
||||||
gen.attach = true;
|
|
||||||
const src = findCurrentGenerateSrc();
|
const src = findCurrentGenerateSrc();
|
||||||
if (src) {
|
if (src) {
|
||||||
|
gen.attach = true;
|
||||||
gen.src = src;
|
gen.src = src;
|
||||||
|
} else {
|
||||||
|
gen.attach = false;
|
||||||
}
|
}
|
||||||
renderBoard();
|
renderBoard();
|
||||||
}
|
}
|
||||||
@@ -4409,7 +4457,8 @@
|
|||||||
if (!ids.length || state.visionHopUsed) {
|
if (!ids.length || state.visionHopUsed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const have = ids.map((id) => slotById(id)).filter((s) => s && s.src);
|
scrubPreviewFromGenerateSlot();
|
||||||
|
const have = ids.map((id) => slotById(id)).filter((s) => s && s.src && !looksLikeModelPreview(s.src));
|
||||||
if (!have.length) {
|
if (!have.length) {
|
||||||
const genSrc = findCurrentGenerateSrc();
|
const genSrc = findCurrentGenerateSrc();
|
||||||
if (ids.includes(GEN_ID) && genSrc) {
|
if (ids.includes(GEN_ID) && genSrc) {
|
||||||
@@ -4421,7 +4470,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!have.length) {
|
if (!have.length) {
|
||||||
setStatus('look_at: those windows are empty');
|
setStatus('look_at: нет реального кадра (превью модели пропущено)');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const already = new Set(attachedSlotIds || []);
|
const already = new Set(attachedSlotIds || []);
|
||||||
@@ -4521,10 +4570,10 @@
|
|||||||
if (!wantedIds.length) {
|
if (!wantedIds.length) {
|
||||||
wantedIds = attachableSlots().map((s) => s.id);
|
wantedIds = attachableSlots().map((s) => s.id);
|
||||||
}
|
}
|
||||||
if (wantsAutoVision() && generateSlot()?.src && !wantedIds.includes(GEN_ID)) {
|
if (wantsAutoVision() && generateSlot()?.src && !looksLikeModelPreview(generateSlot().src) && !wantedIds.includes(GEN_ID)) {
|
||||||
wantedIds.push(GEN_ID);
|
wantedIds.push(GEN_ID);
|
||||||
}
|
}
|
||||||
const visionSlots = wantedIds.map((id) => slotById(id)).filter((s) => s && s.src);
|
const visionSlots = wantedIds.map((id) => slotById(id)).filter((s) => s && s.src && !looksLikeModelPreview(s.src));
|
||||||
let images = null;
|
let images = null;
|
||||||
if (visionSlots.length) {
|
if (visionSlots.length) {
|
||||||
startBusyUi('encoding');
|
startBusyUi('encoding');
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ You are **Swarm Assistent**, a collaborative art director for image generation i
|
|||||||
|
|
||||||
When instructions conflict, apply this order (highest wins):
|
When instructions conflict, apply this order (highest wins):
|
||||||
|
|
||||||
1. **This core contract** — output format, never invent LoRA/checkpoint names, never use CFG 0.
|
1. **This core contract** — output format, never invent LoRA/checkpoint names, never use CFG 0, never depict or request anyone 17 or under (adults only).
|
||||||
2. **Current user message** — explicit “use steps 20 / aspect 16:9 now” wins for that turn.
|
2. **Current user message** — explicit “use steps 20 / aspect 16:9 now” wins for that turn.
|
||||||
3. **Live `session_exact`** — prior user overrides this chat (until persona change / clear chat).
|
3. **Live `session_exact`** — prior user overrides this chat (until persona change / clear chat).
|
||||||
4. **Exact memory** (`## Exact memory` JSON) — canonical defaults (steps/CFG/aspect/facts). Persona overlays are already merged into it.
|
4. **Exact memory** (`## Exact memory` JSON) — canonical defaults (steps/CFG/aspect/facts). Persona overlays are already merged into it.
|
||||||
|
|||||||
@@ -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.
|
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.0** — Config/_base + persona folders, skills, **exact KV memory** + vector memory-seed → SQLite, Ollama `use: chat|memory`, slim inventory via retrieve.
|
**Version 0.7.1** — Exact KV memory + persona overlays; block SwarmUI `ViewSpecial`/model-card previews from Generate + vision.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class SwarmAssistentExtension : Extension
|
|||||||
ExtensionAuthor = "mrleo1nid";
|
ExtensionAuthor = "mrleo1nid";
|
||||||
Description = "Collaborative Krea 2 assistant: Ollama chat, persona presets, vector memory, model cards, Generate loop.";
|
Description = "Collaborative Krea 2 assistant: Ollama chat, persona presets, vector memory, model cards, Generate loop.";
|
||||||
License = "MIT";
|
License = "MIT";
|
||||||
Version = "0.7.0";
|
Version = "0.7.1";
|
||||||
Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory"];
|
Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user