// ---------- Glowing cursor effect ---------- const glowingEffect = document.createElement('div'); glowingEffect.classList.add('glowing-effect', 'js-generated'); document.body.appendChild(glowingEffect); // Update CSS custom properties for the glow position (mouse + touch) function updateGlow(x, y) { glowingEffect.style.setProperty('--x', `${x}px`); glowingEffect.style.setProperty('--y', `${y}px`); } document.addEventListener('mousemove', (e) => updateGlow(e.clientX, e.clientY)); document.addEventListener('touchmove', (e) => { if (e.touches && e.touches[0]) { updateGlow(e.touches[0].clientX, e.touches[0].clientY); } }, { passive: true }); // ---------- Helper utilities ---------- const qs = (id) => document.getElementById(id); const showOutput = (html) => { const outputDiv = qs('output') || (() => { const d = document.createElement('div'); d.id = 'output'; document.body.appendChild(d); return d; })(); outputDiv.innerHTML = html; }; const createDownloadLink = (url, label = 'Download') => { const a = document.createElement('a'); a.href = url; a.textContent = label; a.download = ''; a.className = 'download-link'; return a; }; const createImgPreview = (src, alt = 'preview') => { const img = document.createElement('img'); img.src = src; img.alt = alt; img.style.maxWidth = '320px'; img.style.height = 'auto'; img.style.display = 'block'; img.style.marginTop = '12px'; img.style.borderRadius = '8px'; return img; }; // ---------- Elements (gracefully handle missing elements) ---------- const imageInput = qs('image') || qs('image-input'); // caption image const foregroundInput = qs('foreground'); // foreground for change bg / remove bg const backgroundInput = qs('background'); // background for change bg (optional) const generateCaptionBtn = qs('generate-caption-btn'); const removeBackgroundBtn = qs('remove-background-btn'); const changeBackgroundBtn = qs('change-background-btn'); // ---------- Core request functions using FormData ---------- async function postFormData(url, formData) { const res = await fetch(url, { method: 'POST', body: formData, // do NOT set Content-Type; browser will add the correct boundary }); if (!res.ok) { const text = await res.text().catch(() => ''); throw new Error(`Server responded ${res.status}: ${text}`); } return res.json().catch(() => { throw new Error('Invalid JSON response'); }); } // ---------- Generate Caption ---------- if (generateCaptionBtn) { generateCaptionBtn.addEventListener('click', async (e) => { e.preventDefault(); try { const fileInput = imageInput; if (!fileInput || !fileInput.files || fileInput.files.length === 0) { showOutput('Please choose an image to generate caption.'); return; } showOutput('Generating caption…'); const fd = new FormData(); fd.append('image', fileInput.files[0]); const data = await postFormData('/generate_caption', fd); // Expecting JSON like: { caption: "...", image_url: "..." } but handle flexibly const caption = data.caption || data.text || ''; const imageUrl = data.image_url || data.result_url || data.output_url || null; let html = `Generated Caption:
${caption || '(no caption returned)'}
`; if (imageUrl) { const img = createImgPreview(imageUrl, 'Generated caption preview'); html += '
'; // separator // we will set outputDiv innerHTML, then append image node and download link } showOutput(html); if (imageUrl) { const outDiv = qs('output'); outDiv.appendChild(createImgPreview(imageUrl, 'Generated caption preview')); outDiv.appendChild(createDownloadLink(imageUrl, 'Download Result Image')); // Optional: add "Copy caption" button if (caption) { const copyBtn = document.createElement('button'); copyBtn.textContent = 'Copy Caption'; copyBtn.style.marginLeft = '8px'; copyBtn.addEventListener('click', () => { navigator.clipboard?.writeText(caption).then(() => { copyBtn.textContent = 'Copied!'; setTimeout(() => copyBtn.textContent = 'Copy Caption', 1500); }).catch(() => { copyBtn.textContent = 'Copy failed'; }); }); outDiv.appendChild(copyBtn); } } } catch (err) { console.error(err); showOutput(`Error generating caption: ${err.message}`); } }); } // ---------- Remove Background ---------- if (removeBackgroundBtn) { removeBackgroundBtn.addEventListener('click', async (e) => { e.preventDefault(); try { // Prefer explicit foreground input; fallback to generic image input const fileInput = foregroundInput || imageInput; if (!fileInput || !fileInput.files || fileInput.files.length === 0) { showOutput('Please choose an image to remove background.'); return; } showOutput('Removing background…'); const fd = new FormData(); fd.append('image', fileInput.files[0]); const data = await postFormData('/remove_background', fd); // Expect JSON like: { output_url: "..." } or { output_path: "..." } const outUrl = data.output_url || data.output_path || data.result_url || null; if (outUrl) { const outHtml = 'Removed Background:'; showOutput(outHtml); const outDiv = qs('output'); outDiv.appendChild(createImgPreview(outUrl, 'Result - background removed')); outDiv.appendChild(createDownloadLink(outUrl, 'Download Result Image')); } else { showOutput('Background removed but server did not return a URL.'); } } catch (err) { console.error(err); showOutput(`Error removing background: ${err.message}`); } }); } // ---------- Change Background ---------- if (changeBackgroundBtn) { changeBackgroundBtn.addEventListener('click', async (e) => { e.preventDefault(); try { const fgInput = foregroundInput || imageInput; if (!fgInput || !fgInput.files || fgInput.files.length === 0) { showOutput('Please choose a foreground image.'); return; } // Option A: use a second file input for background if available // Option B: fallback to a hard-coded URL (if your server supports that) const bgFile = (backgroundInput && backgroundInput.files && backgroundInput.files[0]) || null; const FALLBACK_BACKGROUND_URL = null; // set a URL string here only if your server supports background URLs if (!bgFile && !FALLBACK_BACKGROUND_URL) { showOutput('Please choose a background image (or configure FALLBACK_BACKGROUND_URL in the script).'); return; } showOutput('Changing background…'); const fd = new FormData(); fd.append('foreground', fgInput.files[0]); if (bgFile) { fd.append('background', bgFile); } else { fd.append('background_url', FALLBACK_BACKGROUND_URL); } const data = await postFormData('/change_background', fd); const outUrl = data.output_url || data.output_path || data.result_url || null; if (outUrl) { showOutput('Changed Background:'); const outDiv = qs('output'); outDiv.appendChild(createImgPreview(outUrl, 'Result - background changed')); outDiv.appendChild(createDownloadLink(outUrl, 'Download Result Image')); } else { showOutput('Background changed but server did not return a URL.'); } } catch (err) { console.error(err); showOutput(`Error changing background: ${err.message}`); } }); } // ---------- Accessibility: enable Enter key on focused file inputs when needed ---------- document.addEventListener('keydown', (e) => { if (e.key === 'Enter') { // try to trigger caption generation if that button exists and is visible const active = document.activeElement; if (active && (active.tagName === 'INPUT' && active.type === 'file')) { // don't auto-submit; just do nothing (files require user action) return; } } }); // ---------- Optional: add minimal CSS for the glowing effect if not already in CSS ---------- (function ensureGlowCss() { const id = 'glow-css'; if (document.getElementById(id)) return; const style = document.createElement('style'); style.id = id; style.textContent = ` .glowing-effect { position: fixed; left: 0; top: 0; width: 240px; height: 240px; pointer-events: none; transform: translate(calc(var(--x, 0) - 50%), calc(var(--y, 0) - 50%)); mix-blend-mode: screen; filter: blur(40px); z-index: 9999; transition: transform 0.04s linear; background: radial-gradient(circle at center, rgba(0,150,255,0.18) 0%, rgba(0,150,255,0.06) 40%, transparent 70%); } .glowing-effect.js-generated { opacity: 0.95; } #output { margin: 14px auto; max-width: 720px; text-align: left; } .download-link { display:inline-block; margin-top:8px; padding:8px 12px; background:#007bff; color:#fff; border-radius:6px; text-decoration:none; } .download-link:hover { background:#0056b3; } `; document.head.appendChild(style); })();