Spaces:
Running
Running
| === index.html === | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta name="description" content="Remix images with text prompts using AI models like Gemini and GPT. Drag and drop your images into three spots for creative combinations."> | |
| <meta name="keywords" content="image remixer, AI art, Gemini, GPT, image generation, drag and drop, creative tool"> | |
| <meta name="author" content="Anycoder"> | |
| <title>AI Image Remixer</title> | |
| <link rel="stylesheet" href="assets/css/styles.css"> | |
| <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext x='50%' y='50%' style='dominant-baseline:central;text-anchor:middle;font-size:80px;'%3E🎨%3C/text%3E%3C/svg%3E" type="image/svg+xml"> | |
| </head> | |
| <body> | |
| <header class="site-header"> | |
| <div class="container"> | |
| <h1>AI Image Remixer 🎨</h1> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="anycoder-link" target="_blank" rel="noopener noreferrer">Built with anycoder</a> | |
| </div> | |
| </header> | |
| <main class="container"> | |
| <section class="upload-section"> | |
| <h2>1. Upload or Drop Images</h2> | |
| <div id="upload-dropzone" class="dropzone"> | |
| <p>Drag & drop images here, or click to upload</p> | |
| <input type="file" id="image-upload" accept="image/*" multiple style="display: none;"> | |
| <button id="upload-button" class="btn">Browse Files</button> | |
| </div> | |
| <div id="uploaded-previews" class="uploaded-previews"> | |
| <!-- Uploaded image previews will go here --> | |
| </div> | |
| </section> | |
| <section class="remix-spots-section"> | |
| <h2>2. Place Images in Spots</h2> | |
| <p class="instruction-text">Drag images from the "Uploads" section into these three blank spots.</p> | |
| <div class="remix-spots"> | |
| <div class="image-spot" id="spot-1" data-index="0"> | |
| <span class="spot-label">Spot 1</span> | |
| <img class="spot-image" src="assets/img/placeholder.png" alt="Image spot 1"> | |
| </div> | |
| <div class="image-spot" id="spot-2" data-index="1"> | |
| <span class="spot-label">Spot 2</span> | |
| <img class="spot-image" src="assets/img/placeholder.png" alt="Image spot 2"> | |
| </div> | |
| <div class="image-spot" id="spot-3" data-index="2"> | |
| <span class="spot-label">Spot 3</span> | |
| <img class="spot-image" src="assets/img/placeholder.png" alt="Image spot 3"> | |
| </div> | |
| </div> | |
| </section> | |
| <section class="prompt-model-section"> | |
| <h2>3. Add a Prompt & Select Model</h2> | |
| <div class="prompt-input-group"> | |
| <label for="text-prompt">Text Prompt:</label> | |
| <textarea id="text-prompt" placeholder="Describe the remix, e.g., 'A surreal landscape with elements of all three images, painted in an impressionistic style.'" rows="4"></textarea> | |
| </div> | |
| <div class="model-selection"> | |
| <h3>Choose AI Model:</h3> | |
| <div class="model-options"> | |
| <label class="model-radio"> | |
| <input type="radio" name="ai-model" value="gemini-2" checked> | |
| Gemini-2 | |
| <span class="tooltip">Advanced multimodal reasoning.</span> | |
| </label> | |
| <label class="model-radio"> | |
| <input type="radio" name="ai-model" value="gpt-image-1"> | |
| GPT Image-1 | |
| <span class="tooltip">Powerful image generation.</span> | |
| </label> | |
| </div> | |
| </div> | |
| <button id="remix-button" class="btn btn-primary">Remix Images</button> | |
| <div id="status-message" class="status-message" aria-live="polite"></div> | |
| </section> | |
| <section class="result-section"> | |
| <h2>4. Your Remixed Image</h2> | |
| <div id="remix-result" class="remix-result"> | |
| <img id="result-image" src="assets/img/initial-result.png" alt="Remixed image output" style="display: none;"> | |
| <p id="result-placeholder">Your remixed image will appear here.</p> | |
| </div> | |
| </section> | |
| </main> | |
| <footer class="site-footer"> | |
| <div class="container"> | |
| <p>© 2023 AI Image Remixer. All rights reserved.</p> | |
| </div> | |
| </footer> | |
| <script src="assets/js/script.js"></script> | |
| </body> | |
| </html> | |
| === assets/css/styles.css === | |
| /* Basic Reset & Box Sizing */ | |
| *, *::before, *::after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| /* Base Styles */ | |
| :root { | |
| --primary-color: #6a0dad; /* Dark purple */ | |
| --primary-hover: #5a0ca0; | |
| --secondary-color: #007bff; /* Blue for highlights */ | |
| --text-color: #333; | |
| --light-text-color: #f4f4f4; | |
| --bg-color: #f9f9f9; | |
| --card-bg: #ffffff; | |
| --border-color: #e0e0e0; | |
| --shadow: 0 4px 10px rgba(0, 0, 0, 0.05); | |
| --border-radius: 8px; | |
| --spacing-md: 16px; | |
| --spacing-lg: 24px; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; | |
| line-height: 1.6; | |
| color: var(--text-color); | |
| background-color: var(--bg-color); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: var(--spacing-md); | |
| } | |
| /* Header */ | |
| .site-header { | |
| background-color: var(--primary-color); | |
| color: var(--light-text-color); | |
| padding: var(--spacing-md) 0; | |
| box-shadow: var(--shadow); | |
| } | |
| .site-header .container { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; /* Allow wrapping on smaller screens */ | |
| } | |
| .site-header h1 { | |
| font-size: 1.8em; | |
| margin: 0; | |
| padding-bottom: 5px; /* Add some padding below for mobile */ | |
| } | |
| .anycoder-link { | |
| color: var(--light-text-color); | |
| text-decoration: none; | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| padding: 5px 10px; | |
| border: 1px solid var(--light-text-color); | |
| border-radius: 5px; | |
| transition: background-color 0.3s ease, color 0.3s ease; | |
| } | |
| .anycoder-link:hover { | |
| background-color: var(--light-text-color); | |
| color: var(--primary-color); | |
| } | |
| /* Main Content Sections */ | |
| main { | |
| flex: 1; /* Allows main content to grow and push footer down */ | |
| padding-top: var(--spacing-lg); | |
| padding-bottom: var(--spacing-lg); | |
| } | |
| section { | |
| background-color: var(--card-bg); | |
| padding: var(--spacing-lg); | |
| margin-bottom: var(--spacing-lg); | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow); | |
| } | |
| h2 { | |
| color: var(--primary-color); | |
| font-size: 1.5em; | |
| margin-bottom: var(--spacing-md); | |
| border-bottom: 2px solid var(--border-color); | |
| padding-bottom: 10px; | |
| } | |
| /* Upload Section */ | |
| .upload-section { | |
| text-align: center; | |
| } | |
| .dropzone { | |
| border: 2px dashed var(--border-color); | |
| border-radius: var(--border-radius); | |
| padding: var(--spacing-lg); | |
| text-align: center; | |
| cursor: pointer; | |
| transition: background-color 0.3s ease, border-color 0.3s ease; | |
| margin-bottom: var(--spacing-md); | |
| position: relative; | |
| } | |
| .dropzone.drag-over { | |
| background-color: #f0e6fa; /* Lighter primary color */ | |
| border-color: var(--primary-color); | |
| } | |
| .dropzone p { | |
| margin-bottom: var(--spacing-md); | |
| font-size: 1.1em; | |
| color: #666; | |
| } | |
| .btn { | |
| display: inline-block; | |
| background-color: var(--primary-color); | |
| color: var(--light-text-color); | |
| padding: 10px 20px; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 1em; | |
| transition: background-color 0.3s ease, transform 0.2s ease; | |
| } | |
| .btn:hover { | |
| background-color: var(--primary-hover); | |
| transform: translateY(-2px); | |
| } | |
| .btn-primary { | |
| background-color: var(--secondary-color); | |
| } | |
| .btn-primary:hover { | |
| background-color: #0056b3; | |
| } | |
| .uploaded-previews { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: var(--spacing-md); | |
| justify-content: center; | |
| margin-top: var(--spacing-md); | |
| } | |
| .uploaded-image-wrapper { | |
| position: relative; | |
| width: 100px; | |
| height: 100px; | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--border-radius); | |
| overflow: hidden; | |
| cursor: grab; | |
| box-shadow: 0 2px 5px rgba(0,0,0,0.1); | |
| } | |
| .uploaded-image-wrapper img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| display: block; | |
| } | |
| .remove-image { | |
| position: absolute; | |
| top: 5px; | |
| right: 5px; | |
| background-color: rgba(255, 0, 0, 0.7); | |
| color: white; | |
| border: none; | |
| border-radius: 50%; | |
| width: 20px; | |
| height: 20px; | |
| font-size: 0.8em; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| transition: background-color 0.2s ease; | |
| } | |
| .remove-image:hover { | |
| background-color: rgba(255, 0, 0, 1); | |
| } | |
| /* Remix Spots Section */ | |
| .instruction-text { | |
| font-style: italic; | |
| color: #666; | |
| margin-bottom: var(--spacing-md); | |
| text-align: center; | |
| } | |
| .remix-spots { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: var(--spacing-md); | |
| margin-top: var(--spacing-md); | |
| } | |
| .image-spot { | |
| border: 2px dashed var(--border-color); | |
| border-radius: var(--border-radius); | |
| min-height: 200px; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| text-align: center; | |
| padding: var(--spacing-md); | |
| transition: background-color 0.3s ease, border-color 0.3s ease; | |
| background-color: #fefefe; | |
| position: relative; | |
| overflow: hidden; /* Ensure image doesn't overflow */ | |
| } | |
| .image-spot.drag-over { | |
| background-color: #e6f0fa; /* Lighter blue for spot drag-over */ | |
| border-color: var(--secondary-color); | |
| } | |
| .image-spot .spot-label { | |
| position: absolute; | |
| top: 10px; | |
| left: 10px; | |
| background-color: rgba(0, 0, 0, 0.6); | |
| color: white; | |
| padding: 3px 8px; | |
| border-radius: 5px; | |
| font-size: 0.8em; | |
| z-index: 10; | |
| } | |
| .image-spot .spot-image { | |
| max-width: 100%; | |
| max-height: 180px; /* Constrain image height */ | |
| object-fit: contain; | |
| display: block; | |
| margin-top: 20px; /* Space for label */ | |
| filter: grayscale(80%); /* Placeholder initial look */ | |
| transition: filter 0.3s ease; | |
| } | |
| .image-spot.has-image .spot-image { | |
| filter: grayscale(0%); /* Full color when an image is dropped */ | |
| } | |
| /* Prompt & Model Section */ | |
| .prompt-input-group { | |
| margin-bottom: var(--spacing-lg); | |
| } | |
| .prompt-input-group label { | |
| display: block; | |
| font-weight: bold; | |
| margin-bottom: 8px; | |
| color: var(--primary-color); | |
| } | |
| textarea#text-prompt { | |
| width: 100%; | |
| padding: 12px; | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--border-radius); | |
| font-size: 1em; | |
| font-family: inherit; | |
| resize: vertical; | |
| min-height: 100px; | |
| transition: border-color 0.3s ease; | |
| } | |
| textarea#text-prompt:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(106, 13, 173, 0.2); | |
| } | |
| .model-selection h3 { | |
| font-size: 1.2em; | |
| color: var(--primary-color); | |
| margin-bottom: var(--spacing-md); | |
| } | |
| .model-options { | |
| display: flex; | |
| gap: var(--spacing-md); | |
| flex-wrap: wrap; | |
| margin-bottom: var(--spacing-lg); | |
| } | |
| .model-radio { | |
| display: flex; | |
| align-items: center; | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--border-radius); | |
| padding: 10px 15px; | |
| cursor: pointer; | |
| transition: background-color 0.3s ease, border-color 0.3s ease; | |
| background-color: var(--card-bg); | |
| position: relative; | |
| overflow: visible; /* Allow tooltip to show */ | |
| } | |
| .model-radio:hover { | |
| background-color: #f0f0f0; | |
| } | |
| .model-radio input[type="radio"] { | |
| margin-right: 8px; | |
| accent-color: var(--primary-color); /* Custom color for radio button */ | |
| } | |
| .model-radio input[type="radio"]:checked + span { | |
| font-weight: bold; | |
| color: var(--primary-color); | |
| } | |
| /* Tooltip for model description */ | |
| .model-radio .tooltip { | |
| visibility: hidden; | |
| opacity: 0; | |
| width: 180px; | |
| background-color: rgba(0, 0, 0, 0.8); | |
| color: #fff; | |
| text-align: center; | |
| border-radius: 6px; | |
| padding: 8px 0; | |
| position: absolute; | |
| z-index: 1; | |
| bottom: 125%; /* Position above the text */ | |
| left: 50%; | |
| margin-left: -90px; /* Center the tooltip */ | |
| font-size: 0.8em; | |
| transition: opacity 0.3s; | |
| } | |
| .model-radio .tooltip::after { | |
| content: " "; | |
| position: absolute; | |
| top: 100%; /* At the bottom of the tooltip */ | |
| left: 50%; | |
| margin-left: -5px; | |
| border-width: 5px; | |
| border-style: solid; | |
| border-color: rgba(0, 0, 0, 0.8) transparent transparent transparent; | |
| } | |
| .model-radio:hover .tooltip { | |
| visibility: visible; | |
| opacity: 1; | |
| } | |
| /* Status Message */ | |
| .status-message { | |
| margin-top: var(--spacing-md); | |
| padding: 10px 15px; | |
| border-radius: var(--border-radius); | |
| font-weight: bold; | |
| text-align: center; | |
| display: none; /* Hidden by default */ | |
| } | |
| .status-message.loading { | |
| background-color: #e0f7fa; /* Light blue */ | |
| color: #007bff; | |
| border: 1px solid #007bff; | |
| display: block; | |
| } | |
| .status-message.error { | |
| background-color: #ffebee; /* Light red */ | |
| color: #d32f2f; | |
| border: 1px solid #d32f2f; | |
| display: block; | |
| } | |
| /* Result Section */ | |
| .remix-result { | |
| min-height: 250px; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| border: 2px dashed var(--border-color); | |
| border-radius: var(--border-radius); | |
| background-color: #fefefe; | |
| overflow: hidden; | |
| padding: var(--spacing-md); | |
| } | |
| .remix-result img#result-image { | |
| max-width: 100%; | |
| max-height: 500px; /* Max height for the result image */ | |
| height: auto; | |
| border-radius: var(--border-radius); | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); | |
| } | |
| .remix-result p#result-placeholder { | |
| color: #888; | |
| font-style: italic; | |
| } | |
| /* Footer */ | |
| .site-footer { | |
| background-color: var(--text-color); | |
| color: var(--light-text-color); | |
| text-align: center; | |
| padding: var(--spacing-md) 0; | |
| margin-top: var(--spacing-lg); | |
| } | |
| .site-footer p { | |
| font-size: 0.9em; | |
| } | |
| /* Responsive Adjustments */ | |
| @media (max-width: 768px) { | |
| .site-header .container { | |
| flex-direction: column; | |
| text-align: center; | |
| } | |
| .site-header h1 { | |
| margin-bottom: var(--spacing-md); | |
| } | |
| .remix-spots { | |
| grid-template-columns: 1fr; /* Stack spots vertically */ | |
| } | |
| .model-options { | |
| flex-direction: column; /* Stack model options vertically */ | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .container { | |
| padding: var(--spacing-md); | |
| } | |
| h1 { | |
| font-size: 1.5em; | |
| } | |
| h2 { | |
| font-size: 1.3em; | |
| } | |
| .btn { | |
| width: 100%; | |
| margin-top: var(--spacing-md); | |
| } | |
| .uploaded-image-wrapper { | |
| width: 80px; | |
| height: 80px; | |
| } | |
| } | |
| === assets/js/script.js === | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const uploadInput = document.getElementById('image-upload'); | |
| const uploadButton = document.getElementById('upload-button'); | |
| const uploadDropzone = document.getElementById('upload-dropzone'); | |
| const uploadedPreviews = document.getElementById('uploaded-previews'); | |
| const imageSpots = Array.from(document.querySelectorAll('.image-spot')); | |
| const textPrompt = document.getElementById('text-prompt'); | |
| const remixButton = document.getElementById('remix-button'); | |
| const statusMessage = document.getElementById('status-message'); | |
| const remixResult = document.getElementById('remix-result'); | |
| const resultImage = document.getElementById('result-image'); | |
| const resultPlaceholder = document.getElementById('result-placeholder'); | |
| // Store base64 data for images in spots | |
| const imageSpotData = Array(3).fill(null); | |
| // Store original draggable elements created from uploaded images | |
| const draggableImages = new Map(); // Map<id, {element, src}> | |
| let uploadedImageCounter = 0; | |
| // --- Utility Functions --- | |
| const showStatus = (message, type = 'loading') => { | |
| statusMessage.textContent = message; | |
| statusMessage.className = `status-message ${type}`; | |
| statusMessage.style.display = 'block'; | |
| }; | |
| const hideStatus = () => { | |
| statusMessage.style.display = 'none'; | |
| statusMessage.textContent = ''; | |
| }; | |
| const clearResult = () => { | |
| resultImage.style.display = 'none'; | |
| resultImage.src = ''; | |
| resultPlaceholder.style.display = 'block'; | |
| }; | |
| // --- File Upload Logic --- | |
| uploadButton.addEventListener('click', () => uploadInput.click()); | |
| uploadInput.addEventListener('change', (event) => { | |
| handleFiles(event.target.files); | |
| }); | |
| uploadDropzone.addEventListener('dragover', (event) => { | |
| event.preventDefault(); | |
| uploadDropzone.classList.add('drag-over'); | |
| }); | |
| uploadDropzone.addEventListener('dragleave', () => { | |
| uploadDropzone.classList.remove('drag-over'); | |
| }); | |
| uploadDropzone.addEventListener('drop', (event) => { | |
| event.preventDefault(); | |
| uploadDropzone.classList.remove('drag-over'); | |
| handleFiles(event.dataTransfer.files); | |
| }); | |
| function handleFiles(files) { | |
| if (files.length === 0) return; | |
| Array.from(files).forEach(file => { | |
| if (!file.type.startsWith('image/')) return; | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| const imgId = `uploaded-img-${uploadedImageCounter++}`; | |
| createDraggableImage(e.target.result, imgId); | |
| }; | |
| reader.readAsDataURL(file); | |
| }); | |
| } | |
| function createDraggableImage(src, id) { | |
| const wrapper = document.createElement('div'); | |
| wrapper.className = 'uploaded-image-wrapper'; | |
| wrapper.draggable = true; | |
| wrapper.id = id; | |
| const img = document.createElement('img'); | |
| img.src = src; | |
| img.alt = `Uploaded image ${id}`; | |
| const removeBtn = document.createElement('button'); | |
| removeBtn.className = 'remove-image'; | |
| removeBtn.textContent = 'x'; | |
| removeBtn.title = 'Remove image'; | |
| removeBtn.addEventListener('click', (e) => { | |
| e.stopPropagation(); // Prevent drag event from firing | |
| wrapper.remove(); | |
| draggableImages.delete(id); | |
| // Also check if this image was in any spot and remove it | |
| for (let i = 0; i < imageSpotData.length; i++) { | |
| if (imageSpotData[i] && imageSpotData[i].id === id) { | |
| clearImageSpot(imageSpots[i], i); | |
| } | |
| } | |
| }); | |
| wrapper.appendChild(img); | |
| wrapper.appendChild(removeBtn); | |
| uploadedPreviews.appendChild(wrapper); | |
| draggableImages.set(id, { element: wrapper, src: src }); | |
| wrapper.addEventListener('dragstart', (e) => { | |
| e.dataTransfer.setData('text/plain', id); | |
| e.dataTransfer.effectAllowed = 'copyMove'; | |
| // Optional: add a class to the original to make it transparent or similar | |
| // e.target.classList.add('dragging'); | |
| }); | |
| // wrapper.addEventListener('dragend', (e) => { | |
| // e.target.classList.remove('dragging'); | |
| // }); | |
| } | |
| // --- Image Spot Drag & Drop Logic --- | |
| imageSpots.forEach((spot) => { | |
| spot.addEventListener('dragover', (event) => { | |
| event.preventDefault(); | |
| spot.classList.add('drag-over'); | |
| event.dataTransfer.dropEffect = 'copy'; | |
| }); | |
| spot.addEventListener('dragleave', () => { | |
| spot.classList.remove('drag-over'); | |
| }); | |
| spot.addEventListener('drop', (event) => { | |
| event.preventDefault(); | |
| spot.classList.remove('drag-over'); | |
| const draggedId = event.dataTransfer.getData('text/plain'); | |
| const draggedImageData = draggableImages.get(draggedId); | |
| if (draggedImageData) { | |
| const spotIndex = parseInt(spot.dataset.index); | |
| renderImageInSpot(spot, draggedImageData.src); | |
| imageSpotData[spotIndex] = { src: draggedImageData.src, id: draggedId }; | |
| } | |
| }); | |
| }); | |
| function renderImageInSpot(spotElement, imgSrc) { | |
| const imgElement = spotElement.querySelector('.spot-image'); | |
| imgElement.src = imgSrc; | |
| spotElement.classList.add('has-image'); | |
| imgElement.alt = `Image in spot ${spotElement.dataset.index + 1}`; | |
| // Remove old image's alt if it exists and wasn't placeholder. | |
| } | |
| function clearImageSpot(spotElement, spotIndex) { | |
| const imgElement = spotElement.querySelector('.spot-image'); | |
| imgElement.src = 'assets/img/placeholder.png'; // Reset to placeholder | |
| spotElement.classList.remove('has-image'); | |
| imgElement.alt = `Image spot ${spotIndex + 1}`; | |
| imageSpotData[spotIndex] = null; | |
| } | |
| // --- Remix Logic --- | |
| remixButton.addEventListener('click', remixImages); | |
| async function remixImages() { | |
| hideStatus(); | |
| clearResult(); | |
| const images = imageSpotData.filter(data => data !== null); | |
| const prompt = textPrompt.value.trim(); | |
| const selectedModel = document.querySelector('input[name="ai-model"]:checked').value; | |
| if (images.length === 0) { | |
| showStatus('Please drag at least one image into a spot.', 'error'); | |
| return; | |
| } | |
| if (!prompt) { | |
| showStatus('Please enter a text prompt.', 'error'); | |
| return; | |
| } | |
| showStatus(`Remixing with ${selectedModel}...`, 'loading'); | |
| try { | |
| // Simulate API call | |
| await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate network delay | |
| // In a real application, you would send `images` (base64 or URLs), `prompt`, and `selectedModel` | |
| // to a backend API that integrates with Gemini-2 or GPT Image-1. | |
| // The backend would then return the generated image's URL or base64. | |
| // For simulation, we'll use a placeholder image based on the model | |
| const placeholderResult = selectedModel === 'gemini-2' | |
| ? 'https://picsum.photos/seed/gemini/800/600?grayscale' // A bit more abstract | |
| : 'https://picsum.photos/seed/gpt/800/600'; // Standard realistic | |
| resultImage.src = placeholderResult; | |
| resultImage.style.display = 'block'; | |
| resultPlaceholder.style.display = 'none'; | |
| showStatus('Remix successful!', 'success'); | |
| statusMessage.style.backgroundColor = '#d4edda'; // Light green for success | |
| statusMessage.style.color = '#155724'; | |
| statusMessage.style.borderColor = '#28a745'; | |
| } catch (error) { | |
| console.error('Remix error:', error); | |
| showStatus('Failed to remix images. Please try again.', 'error'); | |
| } | |
| } | |
| }); | |
| // Initial state for result section | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const resultImage = document.getElementById('result-image'); | |
| const resultPlaceholder = document.getElementById('result-placeholder'); | |
| resultImage.style.display = 'none'; | |
| resultPlaceholder.style.display = 'block'; | |
| }); | |
| === assets/img/placeholder.png === | |
| iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQMAAABHRxZqAAAAA1BMVEWAgIBN1FfXAAAAFUlEQVR4XnOgWAAAAqIApQAAAD8JvL4AAAAASUVORK5CYII= | |
| === assets/img/initial-result.png === | |
| iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQMAAABHRxZqAAAAA1BMVEWAgIBN1FfXAAAAFUlEQVR4XnOgWAAAAqIApQAAAD8JvL4AAAAASUVORK5CYII= |