() => { function init() { if (window.__qwenInitDone) return; // Dual-skin: ensure boot ran (HF load order can race). Removes unused shell. if (typeof window.__qwenActivateUiSkin === 'function' && !window.__qwenUiSkin) { window.__qwenActivateUiSkin(); } if (!window.__qwenUiSkin) { const dual = document.getElementById('skin-desktop') || document.getElementById('skin-phone'); if (dual) { setTimeout(init, 50); return; } } const galleryGrid = document.getElementById('image-gallery-grid'); const dropZone = document.getElementById('gallery-drop-zone'); const uploadPrompt = document.getElementById('upload-prompt'); const uploadClick = document.getElementById('upload-click-area'); const fileInput = document.getElementById('custom-file-input'); const btnUpload = document.getElementById('tb-upload'); const btnRemove = document.getElementById('tb-remove'); const btnClear = document.getElementById('tb-clear'); const promptInput = document.getElementById('custom-prompt-input'); const loraSelect = document.getElementById('custom-lora-select'); const packSelect = document.getElementById('custom-prompt-pack-select'); const aspectSelect = document.getElementById('custom-aspect-select'); const sizeSelect = document.getElementById('custom-size-select'); const runBtnEl = document.getElementById('custom-run-btn'); const imgCountTb = document.getElementById('tb-image-count'); const imgCountSb = document.getElementById('sb-image-count'); if (!galleryGrid || !fileInput || !dropZone) { setTimeout(init, 250); return; } window.__qwenInitDone = true; // HF: re-pin floating Edit after UI is live (transform ancestors break fixed) if (typeof window.__qwenPinPhoneRunBar === 'function') { window.__qwenPinPhoneRunBar(); setTimeout(window.__qwenPinPhoneRunBar, 300); } window.__toggleAdvancedSettings = function() { const group = document.getElementById('advanced-settings'); const toggle = document.getElementById('advanced-settings-toggle'); if (!group) return; const open = group.classList.toggle('open'); if (toggle) toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); }; let images = []; window.__uploadedImages = images; let selectedIdx = -1; let toastTimer = null; const IMAGE_SIZE_BASE = {'x-small':512,'small':768,'normal':1024,'large':1280,'x-large':1536}; const MAX_SOURCE_SIDE = 4000; const SIZE_LABELS = { original: 'Original (source pixels)', 'x-small': 'X-Small (thumbnail)', small: 'Small', normal: 'Normal', large: 'Large', 'x-large': 'X-Large', }; function round8(n) { return Math.max(8, Math.floor(Number(n) / 8) * 8); } function capSourceDims(w, h) { const longSide = Math.max(w, h); if (!longSide || longSide <= MAX_SOURCE_SIDE) return [w, h]; const s = MAX_SOURCE_SIDE / longSide; return [Math.max(1, Math.round(w * s)), Math.max(1, Math.round(h * s))]; } function computeOutputDims(srcW, srcH, aspect, size) { if (!srcW || !srcH) return null; if (size === 'original') { let [w, h] = capSourceDims(srcW, srcH); const longSide = Math.max(w, h); if (aspect === 'square') return [round8(longSide), round8(longSide)]; if (aspect === 'wide') return [round8(longSide), round8(longSide * 9 / 16)]; if (aspect === 'portrait') return [round8(longSide * 9 / 16), round8(longSide)]; return [round8(w), round8(h)]; } const base = IMAGE_SIZE_BASE[size] || 1024; const scale = base / 1024; if (aspect === 'square') return [round8(base), round8(base)]; if (aspect === 'wide') return [round8(1344 * scale), round8(768 * scale)]; if (aspect === 'portrait') return [round8(768 * scale), round8(1344 * scale)]; if (srcW >= srcH) { const tw = base; return [round8(tw), round8(tw * srcH / srcW)]; } const th = base; return [round8(th * srcW / srcH), round8(th)]; } function formatDims(w, h) { return w + ' \u00d7 ' + h; } function getAspect() { return aspectSelect ? aspectSelect.value : 'original'; } function getSize() { return sizeSelect ? sizeSelect.value : 'normal'; } function updatePredictedSizeUI() { const outEl = document.getElementById('output-pred-dims'); const sizeEl = document.getElementById('size-pred-dims'); const first = images.length ? images[0] : null; const srcW = first && first.w ? first.w : 0; const srcH = first && first.h ? first.h : 0; const hasSrc = srcW > 0 && srcH > 0; const aspect = getAspect(); const size = getSize(); // Dynamic size-menu labels (show predicted W×H when image #1 is known) if (sizeSelect) { Array.from(sizeSelect.options).forEach(opt => { const key = opt.value; const baseLabel = SIZE_LABELS[key] || key; if (!hasSrc) { if (key === 'original') opt.textContent = baseLabel; else if (key === 'x-small') opt.textContent = 'X-Small (thumbnail \u00b7 512)'; else if (key === 'small') opt.textContent = 'Small (768)'; else if (key === 'normal') opt.textContent = 'Normal (1024)'; else if (key === 'large') opt.textContent = 'Large (1280)'; else if (key === 'x-large') opt.textContent = 'X-Large (1536)'; else opt.textContent = baseLabel; return; } const dims = computeOutputDims(srcW, srcH, aspect, key); if (dims) opt.textContent = baseLabel + ' \u2014 ' + formatDims(dims[0], dims[1]); else opt.textContent = baseLabel; }); } if (!hasSrc) { if (outEl) { outEl.hidden = true; outEl.textContent = ''; } if (sizeEl) { sizeEl.hidden = true; sizeEl.textContent = ''; } return; } const pred = computeOutputDims(srcW, srcH, aspect, size); if (!pred) return; const txt = formatDims(pred[0], pred[1]); if (outEl) { outEl.hidden = false; outEl.textContent = txt; } if (sizeEl) { sizeEl.hidden = false; sizeEl.textContent = 'Predicted output: ' + txt + (size === 'original' && Math.max(srcW, srcH) > MAX_SOURCE_SIDE ? ' (source capped at ' + MAX_SOURCE_SIDE + ' long side)' : ''); } } /* ── Force dark + blue styles on elements that browsers may override ── */ function enforceDarkStyles() { document.querySelectorAll('.lora-selector-card').forEach(el => { el.style.setProperty('background','#0f0f13','important'); }); document.querySelectorAll('.lora-selector-body').forEach(el => { el.style.setProperty('background','#0f0f13','important'); }); document.querySelectorAll('.lora-select-label').forEach(el => { el.style.setProperty('color','#71717a','important'); el.style.setProperty('-webkit-text-fill-color','#71717a','important'); }); [ document.getElementById('custom-lora-select'), document.getElementById('custom-aspect-select'), document.getElementById('custom-size-select'), ].forEach(sel => { if (!sel) return; sel.style.setProperty('background-color','#09090b','important'); sel.style.setProperty('color','#e4e4e7','important'); sel.style.setProperty('-webkit-text-fill-color','#e4e4e7','important'); sel.style.setProperty('border-color','#3f3f46','important'); }); const ghBtn = document.querySelector('.gh-btn'); if (ghBtn) { ghBtn.style.setProperty('background','#1E90FF','important'); ghBtn.style.setProperty('color','#ffffff','important'); ghBtn.style.setProperty('-webkit-text-fill-color','#ffffff','important'); ghBtn.style.setProperty('border-color','rgba(255,255,255,.18)','important'); ghBtn.style.setProperty('box-shadow','0 2px 10px rgba(30,144,255,.45)','important'); const svg = ghBtn.querySelector('svg'); if (svg) svg.style.setProperty('fill','#ffffff','important'); const span = ghBtn.querySelector('span'); if (span) { span.style.setProperty('color','#ffffff','important'); span.style.setProperty('-webkit-text-fill-color','#ffffff','important'); } } const shell = document.querySelector('.app-shell'); const header = document.querySelector('.app-header'); const toolbar = document.querySelector('.app-toolbar'); if (shell) shell.style.setProperty('background','#18181b','important'); if (header) header.style.setProperty('background','#18181b','important'); if (toolbar) toolbar.style.setProperty('background','#18181b','important'); } enforceDarkStyles(); setInterval(enforceDarkStyles, 1000); const ghBtn = document.querySelector('.gh-btn'); if (ghBtn) { ghBtn.addEventListener('mouseenter', () => { ghBtn.style.setProperty('background','#47A3FF','important'); ghBtn.style.setProperty('color','#ffffff','important'); ghBtn.style.setProperty('-webkit-text-fill-color','#ffffff','important'); ghBtn.style.setProperty('transform','translateY(-1px)','important'); ghBtn.style.setProperty('box-shadow','0 5px 18px rgba(30,144,255,.6)','important'); }); ghBtn.addEventListener('mouseleave', () => { ghBtn.style.setProperty('background','#1E90FF','important'); ghBtn.style.setProperty('color','#ffffff','important'); ghBtn.style.setProperty('-webkit-text-fill-color','#ffffff','important'); ghBtn.style.setProperty('transform','translateY(0)','important'); ghBtn.style.setProperty('box-shadow','0 2px 10px rgba(30,144,255,.45)','important'); }); ghBtn.addEventListener('mousedown', () => { ghBtn.style.setProperty('background','#1873CC','important'); ghBtn.style.setProperty('transform','translateY(0)','important'); }); ghBtn.addEventListener('mouseup', () => { ghBtn.style.setProperty('background','#47A3FF','important'); }); } function showToast(message, type) { let toast = document.getElementById('app-toast'); if (!toast) { toast = document.createElement('div'); toast.id = 'app-toast'; toast.className = 'toast-notification'; toast.innerHTML = ''; document.body.appendChild(toast); } const icon = toast.querySelector('.toast-icon'); const text = toast.querySelector('.toast-text'); toast.className = 'toast-notification ' + (type || 'error'); icon.textContent = type === 'warning' ? '\u26A0' : type === 'info' ? '\u2139' : '\u2717'; text.textContent = message; if (toastTimer) clearTimeout(toastTimer); void toast.offsetWidth; toast.classList.add('visible'); toastTimer = setTimeout(() => toast.classList.remove('visible'), 3500); } window.__showToast = showToast; function flashPromptError() { if (!promptInput) return; promptInput.classList.add('error-flash'); promptInput.focus(); setTimeout(() => promptInput.classList.remove('error-flash'), 800); } function setGradioValue(containerId, value) { const container = document.getElementById(containerId); if (!container) return; container.querySelectorAll('input, textarea').forEach(el => { if (el.type === 'file' || el.type === 'range' || el.type === 'checkbox') return; const proto = el.tagName === 'TEXTAREA' ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype; const ns = Object.getOwnPropertyDescriptor(proto, 'value'); if (ns && ns.set) { ns.set.call(el, value); el.dispatchEvent(new Event('input', {bubbles:true, composed:true})); el.dispatchEvent(new Event('change', {bubbles:true, composed:true})); } }); } window.__setGradioValue = setGradioValue; function syncImagesToGradio() { window.__uploadedImages = images; const b64Array = images.map(img => img.b64); setGradioValue('hidden-images-b64', JSON.stringify(b64Array)); updateCounts(); } function syncPromptToGradio() { if (promptInput) setGradioValue('prompt-gradio-input', promptInput.value); } function syncLoraToGradio() { if (!loraSelect) return; const container = document.getElementById('gradio-lora'); if (!container) return; container.querySelectorAll('input').forEach(el => { const ns = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); if (ns && ns.set) { ns.set.call(el, loraSelect.value); el.dispatchEvent(new Event('input', {bubbles:true, composed:true})); el.dispatchEvent(new Event('change', {bubbles:true, composed:true})); } }); } function syncPromptPackToGradio() { if (!packSelect) return; const container = document.getElementById('gradio-prompt-pack'); if (!container) return; container.querySelectorAll('input').forEach(el => { const ns = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); if (ns && ns.set) { ns.set.call(el, packSelect.value); el.dispatchEvent(new Event('input', {bubbles:true, composed:true})); el.dispatchEvent(new Event('change', {bubbles:true, composed:true})); } }); } function syncAspectToGradio() { if (!aspectSelect) return; const container = document.getElementById('gradio-aspect'); if (!container) return; container.querySelectorAll('input').forEach(el => { const ns = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); if (ns && ns.set) { ns.set.call(el, aspectSelect.value); el.dispatchEvent(new Event('input', {bubbles:true, composed:true})); el.dispatchEvent(new Event('change', {bubbles:true, composed:true})); } }); } function syncSizeToGradio() { if (!sizeSelect) return; const container = document.getElementById('gradio-size'); if (!container) return; container.querySelectorAll('input').forEach(el => { const ns = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); if (ns && ns.set) { ns.set.call(el, sizeSelect.value); el.dispatchEvent(new Event('input', {bubbles:true, composed:true})); el.dispatchEvent(new Event('change', {bubbles:true, composed:true})); } }); } const MAX_IMAGES = 2; function updateCounts() { const n = images.length; const txt = n > 0 ? n + ' image' + (n > 1 ? 's' : '') + ' (max ' + MAX_IMAGES + ')' : 'No images'; if (imgCountTb) imgCountTb.textContent = n > 0 ? n + ' image' + (n > 1 ? 's' : '') : 'No images'; if (imgCountSb) imgCountSb.textContent = n > 0 ? n + ' / ' + MAX_IMAGES + ' images' : 'No images uploaded'; } function addImage(b64, name) { if (images.length >= MAX_IMAGES) { showToast('Maximum ' + MAX_IMAGES + ' images. Remove one to add another.', 'warning'); return false; } const entry = {id: Date.now() + Math.random(), b64, name, w: 0, h: 0}; images.push(entry); renderGallery(); syncImagesToGradio(); updatePredictedSizeUI(); const probe = new Image(); probe.onload = () => { entry.w = probe.naturalWidth || 0; entry.h = probe.naturalHeight || 0; renderGallery(); updatePredictedSizeUI(); }; probe.onerror = () => { updatePredictedSizeUI(); }; probe.src = b64; return true; } window.__addImage = addImage; function removeImage(idx) { images.splice(idx, 1); if (selectedIdx === idx) selectedIdx = -1; else if (selectedIdx > idx) selectedIdx--; renderGallery(); syncImagesToGradio(); updatePredictedSizeUI(); } function clearAll() { images = []; window.__uploadedImages = images; selectedIdx = -1; renderGallery(); syncImagesToGradio(); updatePredictedSizeUI(); } window.__clearAll = clearAll; function renderGallery() { if (images.length === 0) { galleryGrid.innerHTML = ''; galleryGrid.style.display = 'none'; if (uploadPrompt) uploadPrompt.style.display = ''; updatePredictedSizeUI(); updateCounts(); return; } if (uploadPrompt) uploadPrompt.style.display = 'none'; galleryGrid.style.display = 'grid'; let html = ''; images.forEach((img, i) => { const sel = i === selectedIdx ? ' selected' : ''; const dimTxt = (img.w && img.h) ? formatDims(img.w, img.h) : '\u2026'; const role = i === 0 ? 'Main' : 'Ref'; html += '