stable-diffusion-webui
426 строк · 12.4 Кб
1// various functions for interaction with ui.py not large enough to warrant putting them in separate files
2
3function set_theme(theme) {4var gradioURL = window.location.href;5if (!gradioURL.includes('?__theme=')) {6window.location.replace(gradioURL + '?__theme=' + theme);7}8}
9
10function all_gallery_buttons() {11var allGalleryButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small');12var visibleGalleryButtons = [];13allGalleryButtons.forEach(function(elem) {14if (elem.parentElement.offsetParent) {15visibleGalleryButtons.push(elem);16}17});18return visibleGalleryButtons;19}
20
21function selected_gallery_button() {22return all_gallery_buttons().find(elem => elem.classList.contains('selected')) ?? null;23}
24
25function selected_gallery_index() {26return all_gallery_buttons().findIndex(elem => elem.classList.contains('selected'));27}
28
29function extract_image_from_gallery(gallery) {30if (gallery.length == 0) {31return [null];32}33if (gallery.length == 1) {34return [gallery[0]];35}36
37var index = selected_gallery_index();38
39if (index < 0 || index >= gallery.length) {40// Use the first image in the gallery as the default41index = 0;42}43
44return [gallery[index]];45}
46
47window.args_to_array = Array.from; // Compatibility with e.g. extensions that may expect this to be around48
49function switch_to_txt2img() {50gradioApp().querySelector('#tabs').querySelectorAll('button')[0].click();51
52return Array.from(arguments);53}
54
55function switch_to_img2img_tab(no) {56gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click();57gradioApp().getElementById('mode_img2img').querySelectorAll('button')[no].click();58}
59function switch_to_img2img() {60switch_to_img2img_tab(0);61return Array.from(arguments);62}
63
64function switch_to_sketch() {65switch_to_img2img_tab(1);66return Array.from(arguments);67}
68
69function switch_to_inpaint() {70switch_to_img2img_tab(2);71return Array.from(arguments);72}
73
74function switch_to_inpaint_sketch() {75switch_to_img2img_tab(3);76return Array.from(arguments);77}
78
79function switch_to_extras() {80gradioApp().querySelector('#tabs').querySelectorAll('button')[2].click();81
82return Array.from(arguments);83}
84
85function get_tab_index(tabId) {86let buttons = gradioApp().getElementById(tabId).querySelector('div').querySelectorAll('button');87for (let i = 0; i < buttons.length; i++) {88if (buttons[i].classList.contains('selected')) {89return i;90}91}92return 0;93}
94
95function create_tab_index_args(tabId, args) {96var res = Array.from(args);97res[0] = get_tab_index(tabId);98return res;99}
100
101function get_img2img_tab_index() {102let res = Array.from(arguments);103res.splice(-2);104res[0] = get_tab_index('mode_img2img');105return res;106}
107
108function create_submit_args(args) {109var res = Array.from(args);110
111// As it is currently, txt2img and img2img send back the previous output args (txt2img_gallery, generation_info, html_info) whenever you generate a new image.112// This can lead to uploading a huge gallery of previously generated images, which leads to an unnecessary delay between submitting and beginning to generate.113// I don't know why gradio is sending outputs along with inputs, but we can prevent sending the image gallery here, which seems to be an issue for some.114// If gradio at some point stops sending outputs, this may break something115if (Array.isArray(res[res.length - 3])) {116res[res.length - 3] = null;117}118
119return res;120}
121
122function setSubmitButtonsVisibility(tabname, showInterrupt, showSkip, showInterrupting) {123gradioApp().getElementById(tabname + '_interrupt').style.display = showInterrupt ? "block" : "none";124gradioApp().getElementById(tabname + '_skip').style.display = showSkip ? "block" : "none";125gradioApp().getElementById(tabname + '_interrupting').style.display = showInterrupting ? "block" : "none";126}
127
128function showSubmitButtons(tabname, show) {129setSubmitButtonsVisibility(tabname, !show, !show, false);130}
131
132function showSubmitInterruptingPlaceholder(tabname) {133setSubmitButtonsVisibility(tabname, false, true, true);134}
135
136function showRestoreProgressButton(tabname, show) {137var button = gradioApp().getElementById(tabname + "_restore_progress");138if (!button) return;139
140button.style.display = show ? "flex" : "none";141}
142
143function submit() {144showSubmitButtons('txt2img', false);145
146var id = randomId();147localSet("txt2img_task_id", id);148
149requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() {150showSubmitButtons('txt2img', true);151localRemove("txt2img_task_id");152showRestoreProgressButton('txt2img', false);153});154
155var res = create_submit_args(arguments);156
157res[0] = id;158
159return res;160}
161
162function submit_txt2img_upscale() {163var res = submit(...arguments);164
165res[2] = selected_gallery_index();166
167return res;168}
169
170function submit_img2img() {171showSubmitButtons('img2img', false);172
173var id = randomId();174localSet("img2img_task_id", id);175
176requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() {177showSubmitButtons('img2img', true);178localRemove("img2img_task_id");179showRestoreProgressButton('img2img', false);180});181
182var res = create_submit_args(arguments);183
184res[0] = id;185res[1] = get_tab_index('mode_img2img');186
187return res;188}
189
190function submit_extras() {191showSubmitButtons('extras', false);192
193var id = randomId();194
195requestProgress(id, gradioApp().getElementById('extras_gallery_container'), gradioApp().getElementById('extras_gallery'), function() {196showSubmitButtons('extras', true);197});198
199var res = create_submit_args(arguments);200
201res[0] = id;202
203console.log(res);204return res;205}
206
207function restoreProgressTxt2img() {208showRestoreProgressButton("txt2img", false);209var id = localGet("txt2img_task_id");210
211if (id) {212requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() {213showSubmitButtons('txt2img', true);214}, null, 0);215}216
217return id;218}
219
220function restoreProgressImg2img() {221showRestoreProgressButton("img2img", false);222
223var id = localGet("img2img_task_id");224
225if (id) {226requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() {227showSubmitButtons('img2img', true);228}, null, 0);229}230
231return id;232}
233
234
235/**
236* Configure the width and height elements on `tabname` to accept
237* pasting of resolutions in the form of "width x height".
238*/
239function setupResolutionPasting(tabname) {240var width = gradioApp().querySelector(`#${tabname}_width input[type=number]`);241var height = gradioApp().querySelector(`#${tabname}_height input[type=number]`);242for (const el of [width, height]) {243el.addEventListener('paste', function(event) {244var pasteData = event.clipboardData.getData('text/plain');245var parsed = pasteData.match(/^\s*(\d+)\D+(\d+)\s*$/);246if (parsed) {247width.value = parsed[1];248height.value = parsed[2];249updateInput(width);250updateInput(height);251event.preventDefault();252}253});254}255}
256
257onUiLoaded(function() {258showRestoreProgressButton('txt2img', localGet("txt2img_task_id"));259showRestoreProgressButton('img2img', localGet("img2img_task_id"));260setupResolutionPasting('txt2img');261setupResolutionPasting('img2img');262});263
264
265function modelmerger() {266var id = randomId();267requestProgress(id, gradioApp().getElementById('modelmerger_results_panel'), null, function() {});268
269var res = create_submit_args(arguments);270res[0] = id;271return res;272}
273
274
275function ask_for_style_name(_, prompt_text, negative_prompt_text) {276var name_ = prompt('Style name:');277return [name_, prompt_text, negative_prompt_text];278}
279
280function confirm_clear_prompt(prompt, negative_prompt) {281if (confirm("Delete prompt?")) {282prompt = "";283negative_prompt = "";284}285
286return [prompt, negative_prompt];287}
288
289
290var opts = {};291onAfterUiUpdate(function() {292if (Object.keys(opts).length != 0) return;293
294var json_elem = gradioApp().getElementById('settings_json');295if (json_elem == null) return;296
297var textarea = json_elem.querySelector('textarea');298var jsdata = textarea.value;299opts = JSON.parse(jsdata);300
301executeCallbacks(optionsChangedCallbacks); /*global optionsChangedCallbacks*/302
303Object.defineProperty(textarea, 'value', {304set: function(newValue) {305var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');306var oldValue = valueProp.get.call(textarea);307valueProp.set.call(textarea, newValue);308
309if (oldValue != newValue) {310opts = JSON.parse(textarea.value);311}312
313executeCallbacks(optionsChangedCallbacks);314},315get: function() {316var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');317return valueProp.get.call(textarea);318}319});320
321json_elem.parentElement.style.display = "none";322});323
324onOptionsChanged(function() {325var elem = gradioApp().getElementById('sd_checkpoint_hash');326var sd_checkpoint_hash = opts.sd_checkpoint_hash || "";327var shorthash = sd_checkpoint_hash.substring(0, 10);328
329if (elem && elem.textContent != shorthash) {330elem.textContent = shorthash;331elem.title = sd_checkpoint_hash;332elem.href = "https://google.com/search?q=" + sd_checkpoint_hash;333}334});335
336let txt2img_textarea, img2img_textarea = undefined;337
338function restart_reload() {339document.body.innerHTML = '<h1 style="font-family:monospace;margin-top:20%;color:lightgray;text-align:center;">Reloading...</h1>';340
341var requestPing = function() {342requestGet("./internal/ping", {}, function(data) {343location.reload();344}, function() {345setTimeout(requestPing, 500);346});347};348
349setTimeout(requestPing, 2000);350
351return [];352}
353
354// Simulate an `input` DOM event for Gradio Textbox component. Needed after you edit its contents in javascript, otherwise your edits
355// will only visible on web page and not sent to python.
356function updateInput(target) {357let e = new Event("input", {bubbles: true});358Object.defineProperty(e, "target", {value: target});359target.dispatchEvent(e);360}
361
362
363var desiredCheckpointName = null;364function selectCheckpoint(name) {365desiredCheckpointName = name;366gradioApp().getElementById('change_checkpoint').click();367}
368
369function currentImg2imgSourceResolution(w, h, scaleBy) {370var img = gradioApp().querySelector('#mode_img2img > div[style="display: block;"] img');371return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];372}
373
374function updateImg2imgResizeToTextAfterChangingImage() {375// At the time this is called from gradio, the image has no yet been replaced.376// There may be a better solution, but this is simple and straightforward so I'm going with it.377
378setTimeout(function() {379gradioApp().getElementById('img2img_update_resize_to').click();380}, 500);381
382return [];383
384}
385
386
387
388function setRandomSeed(elem_id) {389var input = gradioApp().querySelector("#" + elem_id + " input");390if (!input) return [];391
392input.value = "-1";393updateInput(input);394return [];395}
396
397function switchWidthHeight(tabname) {398var width = gradioApp().querySelector("#" + tabname + "_width input[type=number]");399var height = gradioApp().querySelector("#" + tabname + "_height input[type=number]");400if (!width || !height) return [];401
402var tmp = width.value;403width.value = height.value;404height.value = tmp;405
406updateInput(width);407updateInput(height);408return [];409}
410
411
412var onEditTimers = {};413
414// calls func after afterMs milliseconds has passed since the input elem has beed enited by user
415function onEdit(editId, elem, afterMs, func) {416var edited = function() {417var existingTimer = onEditTimers[editId];418if (existingTimer) clearTimeout(existingTimer);419
420onEditTimers[editId] = setTimeout(func, afterMs);421};422
423elem.addEventListener("input", edited);424
425return edited;426}
427