Bump Assistent to 0.5: denser Krea packs, slash commands, and chips.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -691,6 +691,53 @@
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.sa-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sa-chip {
|
||||
appearance: none;
|
||||
border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
|
||||
background: color-mix(in srgb, currentColor 6%, transparent);
|
||||
color: inherit;
|
||||
border-radius: 999px;
|
||||
padding: 0.18rem 0.55rem;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
cursor: pointer;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.sa-chip:hover {
|
||||
background: color-mix(in srgb, currentColor 12%, transparent);
|
||||
}
|
||||
|
||||
.sa-chip.sa-chip-active {
|
||||
border-color: color-mix(in srgb, #6cf 55%, currentColor);
|
||||
background: color-mix(in srgb, #6cf 22%, transparent);
|
||||
}
|
||||
|
||||
.sa-chip-sep {
|
||||
width: 1px;
|
||||
height: 1.1rem;
|
||||
background: color-mix(in srgb, currentColor 28%, transparent);
|
||||
margin: 0 0.15rem;
|
||||
}
|
||||
|
||||
.sa-pack-flash {
|
||||
animation: sa-flash 0.85s ease;
|
||||
}
|
||||
|
||||
.sa-system-note {
|
||||
white-space: pre-wrap;
|
||||
opacity: 0.92;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.sa-composer-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
+461
-15
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Swarm Assistent — Krea 2 collaborative chat (Ollama via Swarm API).
|
||||
* v0.4.0: multi-window board, look_at slots, latest-patch buttons, first-run welcome.
|
||||
* v0.5.0: Krea knowledge packs, aspect/vary/lock_seed patches, slash commands, chips.
|
||||
*/
|
||||
(function () {
|
||||
const LS_BASE = 'swarm_assistent_base_url';
|
||||
@@ -17,16 +17,57 @@
|
||||
const GEN_ID = 'generate';
|
||||
const MAX_REF_SLOTS = 4;
|
||||
|
||||
const ASPECT_TABLE = {
|
||||
'1:1': [1024, 1024],
|
||||
'4:3': [1184, 896],
|
||||
'3:2': [1248, 832],
|
||||
'16:9': [1376, 768],
|
||||
'2.35:1': [1568, 672],
|
||||
'4:5': [928, 1152],
|
||||
'2:3': [832, 1248],
|
||||
'9:16': [768, 1376],
|
||||
};
|
||||
|
||||
const PACK_ALIASES = {
|
||||
write: 'write_prompt',
|
||||
write_prompt: 'write_prompt',
|
||||
critique: 'critique_image',
|
||||
critique_image: 'critique_image',
|
||||
compose: 'compose_scene',
|
||||
compose_scene: 'compose_scene',
|
||||
params: 'fix_params',
|
||||
fix_params: 'fix_params',
|
||||
inpaint: 'inpaint_edit',
|
||||
inpaint_edit: 'inpaint_edit',
|
||||
describe: 'describe_ref',
|
||||
describe_ref: 'describe_ref',
|
||||
};
|
||||
|
||||
const WELCOME_HTML = `
|
||||
<div class="sa-welcome-title">Assistent · Krea 2</div>
|
||||
<ul>
|
||||
<li><strong>Generate</strong> слева — живой просмотр текущей генерации. В чат сам не уходит.</li>
|
||||
<li><strong>Ref</strong> — референсы: drop / paste / Snapshot gen / Send to Assistent.</li>
|
||||
<li>Глаз на окне — отправить это изображение мне в vision.</li>
|
||||
<li>Чипсы aspect / seed / Vary — быстрые патчи. В чате: <code>/help</code>.</li>
|
||||
<li>Кнопки патча только у последнего предложения. Пока идёт генерация, Apply + Generate крутит спиннер.</li>
|
||||
</ul>
|
||||
Напиши, что сгенерировать — или кинь референс и попроси правку.`;
|
||||
|
||||
const HELP_TEXT = `Slash-команды (без LLM):
|
||||
/help — этот список
|
||||
/gen — Generate сейчас
|
||||
/look generate|refN — прикрепить окно к vision
|
||||
/init /mask /clear — Init / Mask / Clear Init
|
||||
/interrupt — остановить генерацию
|
||||
/aspect 16:9 — размер из таблицы 1K
|
||||
/seed lock|random — зафиксировать или рандомизировать seed
|
||||
/vary — новый seed, тот же промпт
|
||||
/pack write|critique|compose|params|inpaint|describe
|
||||
/civitai <query> — поиск LoRA (Confirm в чате)
|
||||
|
||||
Чипсы над полем ввода делают то же для aspect / seed / vary.`;
|
||||
|
||||
const state = {
|
||||
history: [],
|
||||
packsLoaded: false,
|
||||
@@ -46,6 +87,7 @@
|
||||
slots: [],
|
||||
selectedSlotId: 'ref1',
|
||||
refSeq: 1,
|
||||
packUserTouched: false,
|
||||
};
|
||||
|
||||
function $(id) {
|
||||
@@ -1151,7 +1193,19 @@
|
||||
obj.slot_to_init != null ||
|
||||
obj.slot_to_mask != null ||
|
||||
obj.snapshot_generate != null ||
|
||||
obj.select_slot != null
|
||||
obj.select_slot != null ||
|
||||
obj.aspect != null ||
|
||||
obj.images != null ||
|
||||
obj.batch != null ||
|
||||
obj.vary != null ||
|
||||
obj.lock_seed != null ||
|
||||
obj.creativity != null ||
|
||||
obj.intensity != null ||
|
||||
obj.complexity != null ||
|
||||
obj.movement != null ||
|
||||
obj.clear_prompt_images != null ||
|
||||
obj.slot_to_prompt_image != null ||
|
||||
obj.pack != null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1176,6 +1230,120 @@
|
||||
return { prose, patch: lastPatch };
|
||||
}
|
||||
|
||||
function normalizeAspect(raw) {
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
let s = String(raw).trim().toLowerCase().replace(/\s+/g, '');
|
||||
if (!s) {
|
||||
return null;
|
||||
}
|
||||
if (s === 'square') {
|
||||
s = '1:1';
|
||||
} else if (s === 'portrait' || s === 'vert') {
|
||||
s = '2:3';
|
||||
} else if (s === 'landscape' || s === 'horiz') {
|
||||
s = '16:9';
|
||||
} else if (s === 'cinematic' || s === 'ultrawide') {
|
||||
s = '2.35:1';
|
||||
}
|
||||
return ASPECT_TABLE[s] ? s : null;
|
||||
}
|
||||
|
||||
function sizeFromAspect(aspect) {
|
||||
const key = normalizeAspect(aspect);
|
||||
return key ? ASPECT_TABLE[key] : null;
|
||||
}
|
||||
|
||||
function guessAspectFromSize(w, h) {
|
||||
const width = parseInt(w, 10);
|
||||
const height = parseInt(h, 10);
|
||||
if (!width || !height) {
|
||||
return null;
|
||||
}
|
||||
let best = null;
|
||||
let bestDist = Infinity;
|
||||
for (const [key, [aw, ah]] of Object.entries(ASPECT_TABLE)) {
|
||||
const dist = Math.abs(width / height - aw / ah) + Math.abs(width - aw) / 4000 + Math.abs(height - ah) / 4000;
|
||||
if (dist < bestDist) {
|
||||
bestDist = dist;
|
||||
best = key;
|
||||
}
|
||||
}
|
||||
return bestDist < 0.12 ? best : null;
|
||||
}
|
||||
|
||||
function clearPromptImagesInBox() {
|
||||
const box = document.getElementById('alt_prompt_textbox') || document.getElementById('input_prompt');
|
||||
if (!box) {
|
||||
return false;
|
||||
}
|
||||
const before = box.value || '';
|
||||
const next = before
|
||||
.replace(/<image\b[^>]*>[\s\S]*?<\/image>/gi, '')
|
||||
.replace(/<image\b[^>]*\/?>/gi, '')
|
||||
.replace(/data:image\/[a-zA-Z0-9.+-]+;base64,[A-Za-z0-9+/=]+/g, '')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim();
|
||||
if (next === before.trim()) {
|
||||
return false;
|
||||
}
|
||||
box.value = next;
|
||||
box.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
box.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
return true;
|
||||
}
|
||||
|
||||
function setPackValue(packName, { flash, user } = {}) {
|
||||
const pack = $('sa_pack');
|
||||
if (!pack || !packName) {
|
||||
return false;
|
||||
}
|
||||
const resolved = PACK_ALIASES[String(packName).trim()] || String(packName).trim();
|
||||
if (![...pack.options].some((o) => o.value === resolved)) {
|
||||
return false;
|
||||
}
|
||||
if (pack.value !== resolved) {
|
||||
pack.value = resolved;
|
||||
saveSettings();
|
||||
}
|
||||
if (user) {
|
||||
state.packUserTouched = true;
|
||||
}
|
||||
if (flash) {
|
||||
pack.classList.add('sa-pack-flash');
|
||||
setTimeout(() => pack.classList.remove('sa-pack-flash'), 900);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function autoSelectPack(text) {
|
||||
if (state.packUserTouched) {
|
||||
return null;
|
||||
}
|
||||
const t = String(text || '').toLowerCase();
|
||||
if (!t.trim()) {
|
||||
return null;
|
||||
}
|
||||
if (/\b(опиши\s+реф|опиши\s+изображ|prompt\s+from\s+image|describe\s+(this|the|ref|image)|reverse\s*prompt)\b/i.test(t)
|
||||
|| /опиши\s+(этот|эту|картинк|референс)/i.test(t)) {
|
||||
return 'describe_ref';
|
||||
}
|
||||
if (/\b(critique|что\s+не\s+так|посмотри|смотри|разбери|критик)\b/i.test(t)) {
|
||||
return 'critique_image';
|
||||
}
|
||||
if (/\b(inpaint|замажь|закрась|руки|лицо|маск|mask|img2img|init\s*image)\b/i.test(t)) {
|
||||
return 'inpaint_edit';
|
||||
}
|
||||
if (/\b(steps?|cfg|seed|sigma|размер|aspect|ширин|высот|resolution|batch)\b/i.test(t)) {
|
||||
return 'fix_params';
|
||||
}
|
||||
if (/\b(сцен|moodboard|атмосфер|compose|scene|мизансцен)\b/i.test(t)) {
|
||||
return 'compose_scene';
|
||||
}
|
||||
return 'write_prompt';
|
||||
}
|
||||
|
||||
function patchHasGenTrigger(patch) {
|
||||
if (!patch) {
|
||||
return false;
|
||||
@@ -1188,16 +1356,21 @@
|
||||
patch.loras ||
|
||||
patch.width != null ||
|
||||
patch.height != null ||
|
||||
patch.aspect != null ||
|
||||
patch.steps != null ||
|
||||
patch.cfg != null ||
|
||||
patch.seed != null ||
|
||||
patch.sigma_shift != null ||
|
||||
patch.images != null ||
|
||||
patch.batch != null ||
|
||||
patch.vary === true ||
|
||||
patch.use_init_image ||
|
||||
patch.clear_init_image ||
|
||||
patch.init_creativity != null ||
|
||||
patch.denoise != null ||
|
||||
patch.use_mask_image ||
|
||||
patch.clear_mask_image
|
||||
patch.clear_mask_image ||
|
||||
patch.clear_prompt_images
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1210,6 +1383,14 @@
|
||||
const doParams = !which || which === 'all' || which === 'size' || which === 'params';
|
||||
const doInit = !which || which === 'all' || which === 'params' || which === 'init';
|
||||
|
||||
if (patch.pack) {
|
||||
setPackValue(patch.pack, { flash: true });
|
||||
}
|
||||
|
||||
if (doPrompt && patch.clear_prompt_images) {
|
||||
clearPromptImagesInBox();
|
||||
}
|
||||
|
||||
if (doPrompt && patch.prompt != null) {
|
||||
const box = document.getElementById('alt_prompt_textbox') || document.getElementById('input_prompt');
|
||||
if (box) {
|
||||
@@ -1263,11 +1444,17 @@
|
||||
}
|
||||
|
||||
if (doParams) {
|
||||
if (patch.width != null) {
|
||||
setVal('input_width', String(patch.width));
|
||||
}
|
||||
if (patch.height != null) {
|
||||
setVal('input_height', String(patch.height));
|
||||
const aspectSize = sizeFromAspect(patch.aspect);
|
||||
if (aspectSize) {
|
||||
setVal('input_width', String(aspectSize[0]));
|
||||
setVal('input_height', String(aspectSize[1]));
|
||||
} else {
|
||||
if (patch.width != null) {
|
||||
setVal('input_width', String(patch.width));
|
||||
}
|
||||
if (patch.height != null) {
|
||||
setVal('input_height', String(patch.height));
|
||||
}
|
||||
}
|
||||
if (patch.steps != null) {
|
||||
setVal('input_steps', String(patch.steps));
|
||||
@@ -1279,7 +1466,14 @@
|
||||
setVal('input_cfg', String(patch.cfg));
|
||||
}
|
||||
}
|
||||
if (patch.seed != null) {
|
||||
if (patch.vary === true) {
|
||||
setVal('input_seed', '-1');
|
||||
} else if (patch.lock_seed === true) {
|
||||
const cur = val('input_seed');
|
||||
if (cur && String(cur) !== '-1') {
|
||||
setVal('input_seed', cur);
|
||||
}
|
||||
} else if (patch.seed != null) {
|
||||
setVal('input_seed', String(patch.seed));
|
||||
}
|
||||
if (patch.sigma_shift != null) {
|
||||
@@ -1293,6 +1487,14 @@
|
||||
if (patch.scheduler != null && document.getElementById('input_scheduler')) {
|
||||
setVal('input_scheduler', String(patch.scheduler));
|
||||
}
|
||||
const batch = patch.images != null ? patch.images : patch.batch;
|
||||
if (batch != null) {
|
||||
if (document.getElementById('input_images')) {
|
||||
setVal('input_images', String(batch));
|
||||
} else if (document.getElementById('input_batchsize')) {
|
||||
setVal('input_batchsize', String(batch));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doInit) {
|
||||
@@ -1361,7 +1563,11 @@
|
||||
setStatus('No image for Mask — drop a mask (white=edit) first');
|
||||
}
|
||||
}
|
||||
if (patch.slot_to_prompt_image) {
|
||||
setStatus('Prompt Images: drop the ref into the Swarm prompt box (no auto helper yet)');
|
||||
}
|
||||
}
|
||||
syncChipHighlight();
|
||||
setStatus('Applied patch');
|
||||
}
|
||||
|
||||
@@ -2019,6 +2225,199 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function applyQuickPatch(patch, note) {
|
||||
const withActions = { ...patch };
|
||||
if (!Array.isArray(withActions.actions) && patchHasGenTrigger(withActions)) {
|
||||
withActions.actions = ['generate'];
|
||||
}
|
||||
await applyPatch(withActions, 'all');
|
||||
setStatus(note || 'Applied');
|
||||
if ($('sa_auto_generate')?.checked) {
|
||||
await runGenerateFromPatch(withActions);
|
||||
}
|
||||
syncChipHighlight();
|
||||
}
|
||||
|
||||
function syncChipHighlight() {
|
||||
const bar = $('sa_chips');
|
||||
if (!bar) {
|
||||
return;
|
||||
}
|
||||
const cur = guessAspectFromSize(val('input_width'), val('input_height'));
|
||||
const seed = val('input_seed');
|
||||
bar.querySelectorAll('[data-aspect]').forEach((btn) => {
|
||||
btn.classList.toggle('sa-chip-active', btn.getAttribute('data-aspect') === cur);
|
||||
});
|
||||
bar.querySelectorAll('[data-seed]').forEach((btn) => {
|
||||
const mode = btn.getAttribute('data-seed');
|
||||
const active = (mode === 'lock' && seed && seed !== '-1') || (mode === 'random' && (!seed || seed === '-1'));
|
||||
btn.classList.toggle('sa-chip-active', active);
|
||||
});
|
||||
}
|
||||
|
||||
function appendSystemNote(text) {
|
||||
const box = $('sa_messages');
|
||||
if (!box) {
|
||||
return;
|
||||
}
|
||||
hideChatEmpty();
|
||||
const div = document.createElement('div');
|
||||
div.className = 'sa-msg assistant sa-system-note';
|
||||
div.textContent = text;
|
||||
box.appendChild(div);
|
||||
box.scrollTop = box.scrollHeight;
|
||||
}
|
||||
|
||||
async function handleSlashCommand(raw) {
|
||||
const text = String(raw || '').trim();
|
||||
if (!text.startsWith('/')) {
|
||||
return false;
|
||||
}
|
||||
const parts = text.slice(1).split(/\s+/);
|
||||
const cmd = (parts[0] || '').toLowerCase();
|
||||
const arg = parts.slice(1).join(' ').trim();
|
||||
|
||||
if (cmd === 'help' || cmd === '?') {
|
||||
appendSystemNote(HELP_TEXT);
|
||||
setStatus('/help');
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'gen' || cmd === 'generate') {
|
||||
const prev = findCurrentGenerateSrc();
|
||||
startBusyUi('generating');
|
||||
state.generating = true;
|
||||
setInterruptVisible(true);
|
||||
if (!triggerGenerate()) {
|
||||
state.generating = false;
|
||||
stopBusyUi('Could not start Generate');
|
||||
return true;
|
||||
}
|
||||
const src = await waitForNewImage(prev);
|
||||
state.generating = false;
|
||||
setInterruptVisible(state.busy);
|
||||
if (src) {
|
||||
const gen = generateSlot();
|
||||
if (gen) {
|
||||
gen.src = src;
|
||||
renderBoard();
|
||||
}
|
||||
stopBusyUi('Generate done');
|
||||
} else {
|
||||
stopBusyUi('Generate finished');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'look') {
|
||||
const id = normalizeSlotId(arg || GEN_ID) || GEN_ID;
|
||||
const slot = slotById(id);
|
||||
if (!slot) {
|
||||
setStatus(`Unknown slot: ${arg || GEN_ID}`);
|
||||
return true;
|
||||
}
|
||||
if (!slot.src && id === GEN_ID) {
|
||||
const src = findCurrentGenerateSrc();
|
||||
if (src) {
|
||||
slot.src = src;
|
||||
}
|
||||
}
|
||||
if (!slot.src) {
|
||||
setStatus(`Slot ${id} is empty`);
|
||||
return true;
|
||||
}
|
||||
slot.attach = true;
|
||||
renderBoard();
|
||||
if ($('sa_input')) {
|
||||
$('sa_input').value = `Look at ${id} and describe what you see.`;
|
||||
}
|
||||
setPackValue('critique_image', { flash: true });
|
||||
await sendChat({ forceSlotIds: [id], skipAutoPack: true });
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'init') {
|
||||
const src = selectedSrc() || findCurrentGenerateSrc();
|
||||
if (!src) {
|
||||
setStatus('No image for Init');
|
||||
return true;
|
||||
}
|
||||
await setInitFromSrc(src);
|
||||
setPackValue('inpaint_edit', { flash: true });
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'mask') {
|
||||
const src = selectedSrc();
|
||||
if (!src) {
|
||||
setStatus('Select a window with a mask image');
|
||||
return true;
|
||||
}
|
||||
await setMaskFromSrc(src);
|
||||
setPackValue('inpaint_edit', { flash: true });
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'clear') {
|
||||
clearInitAndMask();
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'interrupt' || cmd === 'stop') {
|
||||
doInterruptNow();
|
||||
state.busy = false;
|
||||
state.generating = false;
|
||||
setInterruptVisible(false);
|
||||
syncGenerateBusy();
|
||||
syncPatchActionAvailability();
|
||||
stopBusyUi('Interrupted');
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'aspect') {
|
||||
const key = normalizeAspect(arg);
|
||||
if (!key) {
|
||||
setStatus(`Unknown aspect. Try: ${Object.keys(ASPECT_TABLE).join(', ')}`);
|
||||
return true;
|
||||
}
|
||||
await applyQuickPatch({ aspect: key, actions: ['generate'] }, `Aspect ${key}`);
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'seed') {
|
||||
const mode = (arg || 'random').toLowerCase();
|
||||
if (mode === 'lock' || mode === 'keep') {
|
||||
await applyQuickPatch({ lock_seed: true }, 'Seed locked');
|
||||
} else {
|
||||
await applyQuickPatch({ seed: -1, vary: true, actions: ['generate'] }, 'Seed random');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'vary') {
|
||||
await applyQuickPatch({ vary: true, seed: -1, actions: ['generate'] }, 'Vary (new seed)');
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'pack') {
|
||||
if (!setPackValue(arg, { flash: true, user: true })) {
|
||||
setStatus('Pack: write|critique|compose|params|inpaint|describe');
|
||||
} else {
|
||||
setStatus(`Pack → ${$('sa_pack')?.value}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (cmd === 'civitai') {
|
||||
if (!arg) {
|
||||
setStatus('/civitai <query>');
|
||||
return true;
|
||||
}
|
||||
if ($('sa_input')) {
|
||||
$('sa_input').value = `Find a Krea 2 LoRA for: ${arg}`;
|
||||
}
|
||||
setPackValue('write_prompt', { flash: true });
|
||||
await sendChat({
|
||||
skipAutoPack: true,
|
||||
forcedUserText: `Search Civitai for Krea-compatible LoRA: ${arg}. Prefer actions search_civitai.`,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
appendSystemNote(`Unknown command /${cmd}.\n\n${HELP_TEXT}`);
|
||||
setStatus(`Unknown /${cmd}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function maybeVisionHop(patch, attachedSlotIds) {
|
||||
const ids = lookAtIdsFromPatch(patch);
|
||||
if (!ids.length || state.visionHopUsed) {
|
||||
@@ -2058,17 +2457,39 @@
|
||||
}
|
||||
|
||||
async function sendChat(opts = {}) {
|
||||
if (state.busy) {
|
||||
if (state.busy && !opts.fromVisionHop && !opts.fromAutoCritique) {
|
||||
return;
|
||||
}
|
||||
const rawInput = ($('sa_input')?.value || '').trim();
|
||||
const text = (opts.forcedUserText || rawInput).trim();
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!opts.fromAutoCritique && !opts.fromDownload && !opts.fromVisionHop && !opts.skipSlash) {
|
||||
if (rawInput.startsWith('/')) {
|
||||
if ($('sa_input')) {
|
||||
$('sa_input').value = '';
|
||||
}
|
||||
const handled = await handleSlashCommand(rawInput);
|
||||
if (handled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!updateGate()) {
|
||||
setStatus('Select a Krea 2 model');
|
||||
return;
|
||||
}
|
||||
const text = ($('sa_input')?.value || '').trim();
|
||||
if (!text) {
|
||||
return;
|
||||
|
||||
if (!opts.skipAutoPack && !opts.fromAutoCritique && !opts.fromDownload && !opts.fromVisionHop) {
|
||||
const guessed = autoSelectPack(text);
|
||||
if (guessed) {
|
||||
setPackValue(guessed, { flash: true });
|
||||
}
|
||||
}
|
||||
|
||||
const pack = $('sa_pack')?.value || 'write_prompt';
|
||||
const model = $('sa_model')?.value;
|
||||
if (!model) {
|
||||
@@ -2467,13 +2888,14 @@
|
||||
state.history = [];
|
||||
state.critiqueHopUsed = false;
|
||||
state.visionHopUsed = false;
|
||||
state.packUserTouched = false;
|
||||
const box = $('sa_messages');
|
||||
if (box) {
|
||||
box.innerHTML = '';
|
||||
const empty = document.createElement('div');
|
||||
empty.className = 'sa-chat-empty';
|
||||
empty.id = 'sa_chat_empty';
|
||||
empty.innerHTML = '<div class="sa-chat-empty-title">Collaborative Krea 2</div><div class="sa-chat-empty-hint">Write a prompt, drop refs on the board, or send Generate via Send to Assistent.</div>';
|
||||
empty.innerHTML = '<div class="sa-chat-empty-title">Collaborative Krea 2</div><div class="sa-chat-empty-hint">Write a prompt, drop refs, use aspect chips, or type <code>/help</code>.</div>';
|
||||
box.appendChild(empty);
|
||||
}
|
||||
stopBusyUi('');
|
||||
@@ -2487,7 +2909,28 @@
|
||||
});
|
||||
$('sa_base_url')?.addEventListener('change', saveSettings);
|
||||
$('sa_model')?.addEventListener('change', saveSettings);
|
||||
$('sa_pack')?.addEventListener('change', saveSettings);
|
||||
$('sa_pack')?.addEventListener('change', () => {
|
||||
state.packUserTouched = true;
|
||||
saveSettings();
|
||||
});
|
||||
$('sa_chips')?.addEventListener('click', async (e) => {
|
||||
const btn = e.target.closest('.sa-chip');
|
||||
if (!btn || state.busy || state.generating) {
|
||||
return;
|
||||
}
|
||||
const aspect = btn.getAttribute('data-aspect');
|
||||
const seed = btn.getAttribute('data-seed');
|
||||
const vary = btn.getAttribute('data-vary');
|
||||
if (aspect) {
|
||||
await applyQuickPatch({ aspect, actions: ['generate'] }, `Aspect ${aspect}`);
|
||||
} else if (seed === 'lock') {
|
||||
await applyQuickPatch({ lock_seed: true }, 'Seed locked');
|
||||
} else if (seed === 'random') {
|
||||
await applyQuickPatch({ seed: -1, actions: ['generate'] }, 'Seed random');
|
||||
} else if (vary) {
|
||||
await applyQuickPatch({ vary: true, seed: -1, actions: ['generate'] }, 'Vary');
|
||||
}
|
||||
});
|
||||
$('sa_auto_vision')?.addEventListener('change', () => {
|
||||
saveSettings();
|
||||
const gen = generateSlot();
|
||||
@@ -2501,6 +2944,9 @@
|
||||
$('sa_auto_critique')?.addEventListener('change', saveSettings);
|
||||
$('sa_auto_download')?.addEventListener('change', saveSettings);
|
||||
|
||||
syncChipHighlight();
|
||||
setInterval(syncChipHighlight, 2500);
|
||||
|
||||
setInterval(updateGate, 2000);
|
||||
setInterval(syncGenerateSlot, 700);
|
||||
setInterval(() => {
|
||||
|
||||
Reference in New Issue
Block a user