mirror of
https://github.com/vladmandic/automatic
synced 2026-09-03 11:30:46 +02:00
ui performance optimizations
Co-authored-by: Copilot <copilot@github.com> Signed-off-by: vladmandic <mandic00@live.com>
This commit is contained in:
+136
-35
@@ -4,6 +4,10 @@ window.titles = {};
|
||||
let tabSelected = '';
|
||||
let txt2img_textarea;
|
||||
let img2img_textarea;
|
||||
let fontSizeApplyRaf = 0;
|
||||
let pendingFontSize = null;
|
||||
let appliedFontSize = null;
|
||||
let cachedGradioRoot = null;
|
||||
const wait_time = 800;
|
||||
const token_timeouts = {};
|
||||
let uiLoaded = false;
|
||||
@@ -132,18 +136,34 @@ async function setTheme(val, old) {
|
||||
}
|
||||
|
||||
function setFontSize(val, old) {
|
||||
const size = val || opts.font_size;
|
||||
if (size === old) return;
|
||||
document.documentElement.style.setProperty('--font-size', `${size}px`);
|
||||
gradioApp().style.setProperty('--font-size', `${size}px`);
|
||||
gradioApp().style.setProperty('--text-xxs', `${size - 3}px`);
|
||||
gradioApp().style.setProperty('--text-xs', `${size - 2}px`);
|
||||
gradioApp().style.setProperty('--text-sm', `${size - 1}px`);
|
||||
gradioApp().style.setProperty('--text-md', `${size}px`);
|
||||
gradioApp().style.setProperty('--text-lg', `${size + 1}px`);
|
||||
gradioApp().style.setProperty('--text-xl', `${size + 2}px`);
|
||||
gradioApp().style.setProperty('--text-xxl', `${size + 3}px`);
|
||||
log('setFontSize', size);
|
||||
const size = Number(val || opts.font_size);
|
||||
if (!Number.isFinite(size)) return;
|
||||
if (size === old || size === appliedFontSize || size === pendingFontSize) return;
|
||||
pendingFontSize = size;
|
||||
if (fontSizeApplyRaf) return;
|
||||
|
||||
fontSizeApplyRaf = requestAnimationFrame(() => {
|
||||
const t0 = performance.now();
|
||||
fontSizeApplyRaf = 0;
|
||||
const nextSize = pendingFontSize;
|
||||
pendingFontSize = null;
|
||||
if (!Number.isFinite(nextSize) || nextSize === appliedFontSize) return;
|
||||
|
||||
cachedGradioRoot = cachedGradioRoot || gradioApp();
|
||||
const rootStyle = cachedGradioRoot.style;
|
||||
document.documentElement.style.setProperty('--font-size', `${nextSize}px`);
|
||||
rootStyle.setProperty('--font-size', `${nextSize}px`);
|
||||
rootStyle.setProperty('--text-xxs', `${nextSize - 3}px`);
|
||||
rootStyle.setProperty('--text-xs', `${nextSize - 2}px`);
|
||||
rootStyle.setProperty('--text-sm', `${nextSize - 1}px`);
|
||||
rootStyle.setProperty('--text-md', `${nextSize}px`);
|
||||
rootStyle.setProperty('--text-lg', `${nextSize + 1}px`);
|
||||
rootStyle.setProperty('--text-xl', `${nextSize + 2}px`);
|
||||
rootStyle.setProperty('--text-xxl', `${nextSize + 3}px`);
|
||||
appliedFontSize = nextSize;
|
||||
const t1 = performance.now();
|
||||
log('setFontSize', nextSize, `time=${Math.round(t1 - t0)}`);
|
||||
});
|
||||
}
|
||||
|
||||
function switchToTab(tab) {
|
||||
@@ -350,6 +370,28 @@ function clearPrompts(prompt, negative_prompt) {
|
||||
}
|
||||
|
||||
const promptTokenCountUpdateFuncs = {};
|
||||
const registeredPromptTextareas = new WeakSet();
|
||||
const registeredPromptIds = new Set();
|
||||
const pendingCounterPlacement = new Set();
|
||||
const promptRegistrationConfig = [
|
||||
['txt2img_prompt', 'txt2img_token_counter', 'txt2img_token_button'],
|
||||
['txt2img_neg_prompt', 'txt2img_negative_token_counter', 'txt2img_negative_token_button'],
|
||||
['img2img_prompt', 'img2img_token_counter', 'img2img_token_button'],
|
||||
['img2img_neg_prompt', 'img2img_negative_token_counter', 'img2img_negative_token_button'],
|
||||
['control_prompt', 'control_token_counter', 'control_token_button'],
|
||||
['control_neg_prompt', 'control_negative_token_counter', 'control_negative_token_button'],
|
||||
];
|
||||
let promptRegistrationRaf = 0;
|
||||
let promptRegistrationCursor = 0;
|
||||
let promptRegistrationInProgress = false;
|
||||
|
||||
function scheduleIdleUI(task) {
|
||||
if (typeof window.requestIdleCallback === 'function') {
|
||||
window.requestIdleCallback(task, { timeout: 500 });
|
||||
} else {
|
||||
setTimeout(task, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function recalculatePromptTokens(name) {
|
||||
if (promptTokenCountUpdateFuncs[name]) {
|
||||
@@ -427,30 +469,89 @@ function sortUIElements() {
|
||||
log('sortUIElements');
|
||||
}
|
||||
|
||||
onAfterUiUpdate(async () => {
|
||||
async function registerTextarea(id, id_counter, id_button) {
|
||||
const prompt = gradioApp().getElementById(id);
|
||||
if (!prompt) return;
|
||||
const counter = gradioApp().getElementById(id_counter);
|
||||
const localTextarea = gradioApp().querySelector(`#${id} > label > textarea`);
|
||||
if (counter.parentElement === prompt.parentElement) return;
|
||||
prompt.parentElement.insertBefore(counter, prompt);
|
||||
prompt.parentElement.style.position = 'relative';
|
||||
promptTokenCountUpdateFuncs[id] = () => { update_token_counter(id_button); };
|
||||
localTextarea.addEventListener('input', promptTokenCountUpdateFuncs[id]);
|
||||
}
|
||||
|
||||
function registerTextareaCallback() {
|
||||
// sortUIElements();
|
||||
if (promptsInitialized) return;
|
||||
log('initPrompts');
|
||||
registerTextarea('txt2img_prompt', 'txt2img_token_counter', 'txt2img_token_button');
|
||||
registerTextarea('txt2img_neg_prompt', 'txt2img_negative_token_counter', 'txt2img_negative_token_button');
|
||||
registerTextarea('img2img_prompt', 'img2img_token_counter', 'img2img_token_button');
|
||||
registerTextarea('img2img_neg_prompt', 'img2img_negative_token_counter', 'img2img_negative_token_button');
|
||||
registerTextarea('control_prompt', 'control_token_counter', 'control_token_button');
|
||||
registerTextarea('control_neg_prompt', 'control_negative_token_counter', 'control_negative_token_button');
|
||||
promptsInitialized = true;
|
||||
});
|
||||
if (promptRegistrationInProgress) return;
|
||||
|
||||
const app = gradioApp();
|
||||
if (!app) return;
|
||||
|
||||
const registerTextarea = (id, id_counter, id_button) => {
|
||||
const prompt = app.getElementById(id);
|
||||
const counter = app.getElementById(id_counter);
|
||||
const localTextarea = prompt?.querySelector('label > textarea');
|
||||
if (!prompt || !counter || !localTextarea || !prompt.parentElement) return false;
|
||||
|
||||
const promptParent = prompt.parentElement;
|
||||
const needsCounterPlacement = counter.parentElement !== promptParent || counter.nextElementSibling !== prompt;
|
||||
if (needsCounterPlacement && !pendingCounterPlacement.has(id)) {
|
||||
pendingCounterPlacement.add(id);
|
||||
scheduleIdleUI(() => {
|
||||
pendingCounterPlacement.delete(id);
|
||||
const currentPrompt = app.getElementById(id);
|
||||
const currentCounter = app.getElementById(id_counter);
|
||||
if (!currentPrompt || !currentCounter || !currentPrompt.parentElement) return;
|
||||
const currentParent = currentPrompt.parentElement;
|
||||
if (currentCounter.parentElement !== currentParent || currentCounter.nextElementSibling !== currentPrompt) {
|
||||
currentParent.insertBefore(currentCounter, currentPrompt);
|
||||
}
|
||||
if (currentParent.style.position !== 'relative') {
|
||||
currentParent.style.position = 'relative';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!promptTokenCountUpdateFuncs[id]) promptTokenCountUpdateFuncs[id] = () => { update_token_counter(id_button); };
|
||||
if (!registeredPromptTextareas.has(localTextarea)) {
|
||||
localTextarea.addEventListener('input', promptTokenCountUpdateFuncs[id]);
|
||||
registeredPromptTextareas.add(localTextarea);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const runPromptRegistrationStep = () => {
|
||||
promptRegistrationRaf = 0;
|
||||
const total = promptRegistrationConfig.length;
|
||||
let cfg = null;
|
||||
|
||||
// Process one prompt registration per frame to avoid long blocking work.
|
||||
for (let attempts = 0; attempts < total; attempts += 1) {
|
||||
const nextCfg = promptRegistrationConfig[promptRegistrationCursor];
|
||||
promptRegistrationCursor = (promptRegistrationCursor + 1) % total;
|
||||
const [id] = nextCfg;
|
||||
if (!registeredPromptIds.has(id)) {
|
||||
cfg = nextCfg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg) {
|
||||
const [id] = cfg;
|
||||
if (registerTextarea(...cfg)) {
|
||||
registeredPromptIds.add(id);
|
||||
} else {
|
||||
// Prompt not available yet, retry on next onAfterUiUpdate callback.
|
||||
promptRegistrationInProgress = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
promptsInitialized = registeredPromptIds.size === total;
|
||||
if (promptsInitialized) {
|
||||
promptRegistrationInProgress = false;
|
||||
log('initPrompts', registeredPromptIds.size);
|
||||
return;
|
||||
}
|
||||
|
||||
promptRegistrationRaf = requestAnimationFrame(runPromptRegistrationStep);
|
||||
};
|
||||
|
||||
promptRegistrationInProgress = true;
|
||||
promptRegistrationRaf = requestAnimationFrame(runPromptRegistrationStep);
|
||||
}
|
||||
|
||||
onAfterUiUpdate(registerTextareaCallback);
|
||||
|
||||
function update_txt2img_tokens(...args) {
|
||||
update_token_counter('txt2img_token_button');
|
||||
@@ -564,7 +665,7 @@ function createThemeElement() {
|
||||
return el;
|
||||
}
|
||||
|
||||
function toggleCompact(val, old) {
|
||||
async function toggleCompact(val, old) {
|
||||
if (val === old) return;
|
||||
log('toggleCompact', val, old);
|
||||
if (val) {
|
||||
|
||||
Reference in New Issue
Block a user