dikdimon commited on
Commit
2967c40
·
verified ·
1 Parent(s): 8cd20f5

Upload fix.js

Browse files
Files changed (1) hide show
  1. !0000-a1111-fix/javascript/fix.js +506 -0
!0000-a1111-fix/javascript/fix.js ADDED
@@ -0,0 +1,506 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const FIX_TAG = '[a1111-fix]';
5
+ const FIX_VERSION = 'v5.2-hardened';
6
+
7
+ if (window.__a1111_fix_v52_applied) {
8
+ console.warn(FIX_TAG, 'already applied, skipping duplicate load');
9
+ return;
10
+ }
11
+ window.__a1111_fix_v52_applied = true;
12
+
13
+ const wrappedCache = new WeakMap();
14
+ const crashLogOnce = new WeakMap();
15
+ const slowLogOnce = new WeakMap();
16
+
17
+ function markWeakOnce(store, callback, kind) {
18
+ if (typeof callback !== 'function') return false;
19
+ let kinds = store.get(callback);
20
+ if (!kinds) {
21
+ kinds = new Set();
22
+ store.set(callback, kinds);
23
+ }
24
+
25
+ if (kinds.has(kind)) return false;
26
+ kinds.add(kind);
27
+ return true;
28
+ }
29
+
30
+ function isWrappedForKind(callback, kind) {
31
+ return !!(
32
+ callback &&
33
+ typeof callback === 'function' &&
34
+ callback.__a1111_fix_wrapped === true &&
35
+ callback.__a1111_fix_kind === kind &&
36
+ typeof callback.__a1111_fix_original === 'function'
37
+ );
38
+ }
39
+
40
+ function getWrappedCallback(callback, kind, slowThresholdMs) {
41
+ if (typeof callback !== 'function') return callback;
42
+ if (isWrappedForKind(callback, kind)) return callback;
43
+
44
+ let sourceCallback = callback;
45
+ if (
46
+ callback.__a1111_fix_wrapped === true &&
47
+ callback.__a1111_fix_kind === kind &&
48
+ typeof callback.__a1111_fix_original === 'function'
49
+ ) {
50
+ sourceCallback = callback.__a1111_fix_original;
51
+ }
52
+
53
+ let perKind = wrappedCache.get(sourceCallback);
54
+ if (!perKind) {
55
+ perKind = Object.create(null);
56
+ wrappedCache.set(sourceCallback, perKind);
57
+ }
58
+
59
+ if (perKind[kind]) return perKind[kind];
60
+
61
+ const wrapped = function (arg) {
62
+ const t0 = performance.now();
63
+ try {
64
+ return sourceCallback(arg);
65
+ } catch (e) {
66
+ if (markWeakOnce(crashLogOnce, sourceCallback, kind)) {
67
+ console.error(FIX_TAG, kind + ' callback crashed:', sourceCallback.name || '(anonymous)', e);
68
+ }
69
+ } finally {
70
+ const elapsed = performance.now() - t0;
71
+ if (elapsed > slowThresholdMs && markWeakOnce(slowLogOnce, sourceCallback, kind)) {
72
+ console.warn(
73
+ FIX_TAG,
74
+ 'SLOW ' + kind + ': "' + (sourceCallback.name || '(anonymous)') + '" took ' + elapsed.toFixed(0) + 'ms'
75
+ );
76
+ }
77
+ }
78
+ };
79
+
80
+ wrapped.__a1111_fix_wrapped = true;
81
+ wrapped.__a1111_fix_original = sourceCallback;
82
+ wrapped.__a1111_fix_kind = kind;
83
+ perKind[kind] = wrapped;
84
+ return wrapped;
85
+ }
86
+
87
+ function wrapQueue(queue, kind, slowThresholdMs) {
88
+ if (!Array.isArray(queue)) return 0;
89
+
90
+ let wrappedCount = 0;
91
+ for (let i = 0; i < queue.length; i++) {
92
+ if (typeof queue[i] === 'function' && !isWrappedForKind(queue[i], kind)) {
93
+ queue[i] = getWrappedCallback(queue[i], kind, slowThresholdMs);
94
+ wrappedCount++;
95
+ }
96
+ }
97
+ return wrappedCount;
98
+ }
99
+
100
+ function patchQueuePush(queue, kind, slowThresholdMs) {
101
+ if (!Array.isArray(queue) || queue.__a1111_fix_push_patched) return false;
102
+
103
+ const originalPush = queue.push;
104
+ if (typeof originalPush !== 'function') return false;
105
+
106
+ queue.push = function (...items) {
107
+ const wrappedItems = items.map((item) =>
108
+ typeof item === 'function' ? getWrappedCallback(item, kind, slowThresholdMs) : item
109
+ );
110
+ return originalPush.apply(this, wrappedItems);
111
+ };
112
+ queue.__a1111_fix_push_patched = true;
113
+ return true;
114
+ }
115
+
116
+ function safeGradioApp() {
117
+ try {
118
+ if (typeof window.gradioApp === 'function') {
119
+ return window.gradioApp();
120
+ }
121
+ } catch (e) {
122
+ console.warn(FIX_TAG, 'gradioApp() failed while resolving accordion:', e);
123
+ }
124
+ return document;
125
+ }
126
+
127
+ function applyFix1() {
128
+ const originalSchedule = window.scheduleAfterUiUpdateCallbacks;
129
+ if (typeof originalSchedule !== 'function' ||
130
+ typeof window.executeCallbacks !== 'function' ||
131
+ !Array.isArray(window.uiAfterUpdateCallbacks)) {
132
+ console.warn(FIX_TAG, 'scheduleAfterUiUpdateCallbacks/executeCallbacks/uiAfterUpdateCallbacks not found, skipping FIX-1');
133
+ return;
134
+ }
135
+
136
+ if (originalSchedule.__a1111_fix_afterupdate_patched) {
137
+ console.warn(FIX_TAG, 'FIX-1 already patched, skipping duplicate apply');
138
+ return;
139
+ }
140
+
141
+ const MAX_WAIT_MS = 1000;
142
+ let maxWaitTimer = null;
143
+ let running = false;
144
+
145
+ function clearMaxWaitTimer() {
146
+ if (maxWaitTimer) {
147
+ clearTimeout(maxWaitTimer);
148
+ maxWaitTimer = null;
149
+ }
150
+ }
151
+
152
+ function runAfterUpdateNow() {
153
+ clearMaxWaitTimer();
154
+
155
+ const timeoutId = window.uiAfterUpdateTimeout;
156
+ if (timeoutId) {
157
+ clearTimeout(timeoutId);
158
+ window.uiAfterUpdateTimeout = null;
159
+ }
160
+
161
+ if (running) return;
162
+ running = true;
163
+ try {
164
+ if (typeof window.executeCallbacks === 'function') {
165
+ window.executeCallbacks(window.uiAfterUpdateCallbacks);
166
+ }
167
+ } finally {
168
+ running = false;
169
+ }
170
+ }
171
+
172
+ if (!window.executeCallbacks.__a1111_fix_afterupdate_guard) {
173
+ const previousExecuteCallbacks = window.executeCallbacks;
174
+ const guardedExecuteCallbacks = function (queue, arg) {
175
+ if (queue === window.uiAfterUpdateCallbacks) {
176
+ clearMaxWaitTimer();
177
+ }
178
+ return previousExecuteCallbacks(queue, arg);
179
+ };
180
+ guardedExecuteCallbacks.__a1111_fix_afterupdate_guard = true;
181
+ guardedExecuteCallbacks.__a1111_fix_afterupdate_guard_original = previousExecuteCallbacks;
182
+ window.executeCallbacks = guardedExecuteCallbacks;
183
+ }
184
+
185
+ const patchedSchedule = function (...args) {
186
+ const result = originalSchedule.apply(this, args);
187
+
188
+ if (!maxWaitTimer) {
189
+ maxWaitTimer = setTimeout(runAfterUpdateNow, MAX_WAIT_MS);
190
+ }
191
+
192
+ return result;
193
+ };
194
+ patchedSchedule.__a1111_fix_afterupdate_patched = true;
195
+ patchedSchedule.__a1111_fix_afterupdate_original = originalSchedule;
196
+ window.scheduleAfterUiUpdateCallbacks = patchedSchedule;
197
+
198
+ console.log(FIX_TAG, 'FIX-1: bounded after-update max-wait=' + MAX_WAIT_MS + 'ms applied (wrapper mode)');
199
+ }
200
+
201
+ function applyFix2() {
202
+ const configs = [
203
+ { queueName: 'uiLoadedCallbacks', registerName: 'onUiLoaded', slowThresholdMs: 100 },
204
+ { queueName: 'uiAfterUpdateCallbacks', registerName: 'onAfterUiUpdate', slowThresholdMs: 100 },
205
+ { queueName: 'uiUpdateCallbacks', registerName: 'onUiUpdate', slowThresholdMs: 50 },
206
+ { queueName: 'optionsChangedCallbacks', registerName: 'onOptionsChanged', slowThresholdMs: 50 },
207
+ { queueName: 'optionsAvailableCallbacks', registerName: 'onOptionsAvailable', slowThresholdMs: 50 },
208
+ { queueName: 'uiTabChangeCallbacks', registerName: 'onUiTabChange', slowThresholdMs: 50 },
209
+ ];
210
+
211
+ const activeConfigs = [];
212
+ const summary = [];
213
+
214
+ for (const cfg of configs) {
215
+ const queue = window[cfg.queueName];
216
+ const register = window[cfg.registerName];
217
+ if (!Array.isArray(queue) || typeof register !== 'function') {
218
+ continue;
219
+ }
220
+
221
+ const existingCount = wrapQueue(queue, cfg.registerName, cfg.slowThresholdMs);
222
+ patchQueuePush(queue, cfg.registerName, cfg.slowThresholdMs);
223
+
224
+ if (!register.__a1111_fix_register_patched) {
225
+ const originalRegister = register;
226
+ const patchedRegister = function (callback) {
227
+ return originalRegister(getWrappedCallback(callback, cfg.registerName, cfg.slowThresholdMs));
228
+ };
229
+ patchedRegister.__a1111_fix_register_patched = true;
230
+ patchedRegister.__a1111_fix_register_original = originalRegister;
231
+ window[cfg.registerName] = patchedRegister;
232
+ }
233
+
234
+ activeConfigs.push(cfg);
235
+ summary.push(cfg.registerName + '=' + existingCount);
236
+ }
237
+
238
+ if (activeConfigs.length === 0) {
239
+ console.warn(FIX_TAG, 'no callback queues found, skipping FIX-2');
240
+ return;
241
+ }
242
+
243
+ if (typeof window.executeCallbacks === 'function' && !window.executeCallbacks.__a1111_fix_patched) {
244
+ const originalExecuteCallbacks = window.executeCallbacks;
245
+ const patchedExecuteCallbacks = function (queue, arg) {
246
+ for (const cfg of activeConfigs) {
247
+ if (queue === window[cfg.queueName]) {
248
+ wrapQueue(queue, cfg.registerName, cfg.slowThresholdMs);
249
+ break;
250
+ }
251
+ }
252
+ return originalExecuteCallbacks(queue, arg);
253
+ };
254
+ patchedExecuteCallbacks.__a1111_fix_patched = true;
255
+ patchedExecuteCallbacks.__a1111_fix_original = originalExecuteCallbacks;
256
+ window.executeCallbacks = patchedExecuteCallbacks;
257
+ }
258
+
259
+ console.log(FIX_TAG, 'FIX-2: callback guards applied to', summary.join(', '));
260
+ }
261
+
262
+ function applyFix3() {
263
+ if (typeof window.inputAccordionChecked !== 'function') {
264
+ console.warn(FIX_TAG, 'inputAccordionChecked not found, skipping FIX-3');
265
+ return;
266
+ }
267
+
268
+ const warnedOnce = new Set();
269
+
270
+ function isRealAccordion(el) {
271
+ return !!(
272
+ el &&
273
+ el.visibleCheckbox instanceof HTMLInputElement &&
274
+ typeof el.onVisibleCheckboxChange === 'function'
275
+ );
276
+ }
277
+
278
+ function resolveRealAccordion(id) {
279
+ const app = safeGradioApp();
280
+ const direct = app.getElementById ? app.getElementById(id) : null;
281
+ if (isRealAccordion(direct)) return direct;
282
+
283
+ const dotted = app.getElementById ? app.getElementById('.' + id) : null;
284
+ if (isRealAccordion(dotted)) return dotted;
285
+
286
+ if (direct && typeof direct.querySelector === 'function') {
287
+ const nestedCheckbox = direct.querySelector('.input-accordion-checkbox');
288
+ if (nestedCheckbox) {
289
+ const parentAccordion = nestedCheckbox.closest('.input-accordion');
290
+ if (isRealAccordion(parentAccordion)) return parentAccordion;
291
+ }
292
+ }
293
+
294
+ return null;
295
+ }
296
+
297
+ window.inputAccordionChecked = function (id, checked) {
298
+ const realEl = resolveRealAccordion(id);
299
+ if (!realEl) {
300
+ if (!warnedOnce.has(id)) {
301
+ warnedOnce.add(id);
302
+ const app = safeGradioApp();
303
+ const direct = app.getElementById ? app.getElementById(id) : null;
304
+ const dotted = app.getElementById ? app.getElementById('.' + id) : null;
305
+ console.error(
306
+ FIX_TAG, 'FIX-3: cannot resolve accordion for id:', id,
307
+ '\n direct el:', direct,
308
+ '\n direct.visibleCheckbox:', direct && direct.visibleCheckbox,
309
+ '\n direct.visibleCheckbox instanceof HTMLInputElement:',
310
+ direct && (direct.visibleCheckbox instanceof HTMLInputElement),
311
+ '\n dotted el:', dotted
312
+ );
313
+ }
314
+ return;
315
+ }
316
+
317
+ realEl.visibleCheckbox.checked = checked;
318
+ realEl.onVisibleCheckboxChange();
319
+ };
320
+
321
+ console.log(FIX_TAG, 'FIX-3: resilient accordion resolver applied');
322
+ }
323
+
324
+ function applyFix4() {
325
+ window.__a1111ScriptRegistry = window.__a1111ScriptRegistry || {
326
+ mode: 'unknown',
327
+ scripts: {},
328
+ loaded: {},
329
+ errors: {},
330
+ injected_order: [],
331
+ };
332
+
333
+ function registerScriptElement(el) {
334
+ if (!el || el.tagName !== 'SCRIPT') return;
335
+ if (typeof window.__a1111RegisterScript === 'function') {
336
+ window.__a1111RegisterScript(el);
337
+ return;
338
+ }
339
+
340
+ const src = el.getAttribute('src') || '';
341
+ window.__a1111ScriptRegistry.scripts[src] = {
342
+ role: el.getAttribute('data-a1111-role') || 'unknown',
343
+ mode: el.getAttribute('data-a1111-mode') || 'unknown',
344
+ path: el.getAttribute('data-a1111-path') || src,
345
+ basedir: el.getAttribute('data-a1111-basedir') || '',
346
+ };
347
+ if (!window.__a1111ScriptRegistry.injected_order.includes(src)) {
348
+ window.__a1111ScriptRegistry.injected_order.push(src);
349
+ }
350
+ }
351
+
352
+ window.addEventListener('error', function (event) {
353
+ const target = event && event.target;
354
+ if (target && target.tagName === 'SCRIPT') {
355
+ registerScriptElement(target);
356
+ const src = target.getAttribute('src') || '';
357
+ window.__a1111ScriptRegistry.errors[src] = true;
358
+ return;
359
+ }
360
+
361
+ const filename = event && event.filename;
362
+ if (filename) {
363
+ console.error(FIX_TAG, 'window error from script:', filename, event.error || event.message || event);
364
+ }
365
+ }, true);
366
+
367
+ window.addEventListener('unhandledrejection', function (event) {
368
+ console.error(FIX_TAG, 'unhandled promise rejection:', event.reason || event);
369
+ });
370
+
371
+ function summarizeRegistry() {
372
+ const registry = window.__a1111ScriptRegistry || {};
373
+ const scripts = registry.scripts || {};
374
+ const loaded = registry.loaded || {};
375
+ const errors = registry.errors || {};
376
+ const order = registry.injected_order || [];
377
+
378
+ const ok = [];
379
+ const failed = [];
380
+ const pending = [];
381
+
382
+ for (const src of order.length ? order : Object.keys(scripts)) {
383
+ const meta = scripts[src] || {};
384
+ const item = {
385
+ src,
386
+ role: meta.role || 'unknown',
387
+ mode: meta.mode || 'unknown',
388
+ path: meta.path || src,
389
+ };
390
+
391
+ if (errors[src]) {
392
+ failed.push(item);
393
+ } else if (loaded[src]) {
394
+ ok.push(item);
395
+ } else {
396
+ pending.push(item);
397
+ }
398
+ }
399
+
400
+ return { ok, failed, pending, mode: registry.mode || 'unknown' };
401
+ }
402
+
403
+ function summarizeCallbacks() {
404
+ const groups = [
405
+ ['uiLoadedCallbacks', 'onUiLoaded'],
406
+ ['uiAfterUpdateCallbacks', 'onAfterUiUpdate'],
407
+ ['uiUpdateCallbacks', 'onUiUpdate'],
408
+ ['optionsChangedCallbacks', 'onOptionsChanged'],
409
+ ['optionsAvailableCallbacks', 'onOptionsAvailable'],
410
+ ['uiTabChangeCallbacks', 'onUiTabChange'],
411
+ ];
412
+ return groups.map(([queueName, registerName]) => {
413
+ const queue = window[queueName];
414
+ return {
415
+ queue: queueName,
416
+ register: registerName,
417
+ present: Array.isArray(queue),
418
+ count: Array.isArray(queue) ? queue.length : 0,
419
+ };
420
+ });
421
+ }
422
+
423
+ // Backend half of the picture. scripts/backend_watchdog.py exposes
424
+ // this endpoint if it's installed and managed to attach; if it's
425
+ // missing or unreachable this just logs one line and moves on, it
426
+ // never throws. Kept as a separate function (returns a Promise) so
427
+ // __a1111FixReport() below can stay synchronous -- existing callers
428
+ // that read its return value immediately, like the load-event
429
+ // handler a bit further down, keep working unchanged.
430
+ window.__a1111FixBackendStatus = function () {
431
+ return fetch('/internal/a1111-fix/status')
432
+ .then(function (resp) {
433
+ if (!resp.ok) throw new Error('HTTP ' + resp.status);
434
+ return resp.json();
435
+ })
436
+ .then(function (status) {
437
+ console.log(FIX_TAG, 'backend status:', status);
438
+ if (status.queue_lock && status.queue_lock.held) {
439
+ console.warn(
440
+ FIX_TAG,
441
+ 'queue_lock has been held for', status.queue_lock.held_for_seconds + 's',
442
+ 'by', status.queue_lock.owner_thread,
443
+ '(' + status.queue_lock.waiters_now, 'call(s) queued behind it) -- ' +
444
+ 'this blocks BOTH the UI Generate button and /sdapi/v1/* right now.'
445
+ );
446
+ }
447
+ if (Array.isArray(status.currently_importing) && status.currently_importing.length) {
448
+ console.warn(FIX_TAG, 'backend is still importing:', status.currently_importing);
449
+ }
450
+ if (Array.isArray(status.slowest_imports) && status.slowest_imports.length) {
451
+ console.table(status.slowest_imports);
452
+ }
453
+ return status;
454
+ })
455
+ .catch(function (err) {
456
+ // Not fatal -- scripts/backend_watchdog.py may not be
457
+ // installed, or the server may genuinely be unreachable
458
+ // right now, which is itself useful information.
459
+ console.log(FIX_TAG, 'backend status unavailable:', err.message);
460
+ return null;
461
+ });
462
+ };
463
+
464
+ window.__a1111FixReport = function () {
465
+ const report = summarizeRegistry();
466
+ const callbacks = summarizeCallbacks();
467
+ console.log(FIX_TAG, 'loader mode =', report.mode);
468
+ console.log(FIX_TAG, 'loaded scripts =', report.ok.length, 'failed =', report.failed.length, 'pending =', report.pending.length);
469
+ console.table(callbacks);
470
+
471
+ if (report.failed.length) {
472
+ console.warn(FIX_TAG, 'failed scripts:');
473
+ console.table(report.failed);
474
+ }
475
+ if (report.pending.length) {
476
+ console.warn(FIX_TAG, 'pending/unconfirmed scripts:');
477
+ console.table(report.pending);
478
+ }
479
+ if (!report.failed.length && !report.pending.length) {
480
+ console.log(FIX_TAG, 'all tracked scripts loaded cleanly');
481
+ }
482
+
483
+ window.__a1111FixBackendStatus();
484
+
485
+ return { ...report, callbacks };
486
+ };
487
+
488
+ window.addEventListener('load', function () {
489
+ setTimeout(function () {
490
+ const report = window.__a1111FixReport();
491
+ if (report.failed.length || report.pending.length) {
492
+ console.warn(FIX_TAG, 'FIX-4: loader diagnostics detected script issues; inspect __a1111FixReport() output');
493
+ }
494
+ }, 1500);
495
+ }, { once: true });
496
+
497
+ console.log(FIX_TAG, 'FIX-4: loader diagnostics ready');
498
+ }
499
+
500
+ applyFix1();
501
+ applyFix2();
502
+ applyFix3();
503
+ applyFix4();
504
+
505
+ console.log(FIX_TAG, FIX_VERSION, 'ready');
506
+ })();