| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Describe Anything Model</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .gradient-bg { |
| background: linear-gradient(135deg, #6b73ff 0%, #000dff 100%); |
| } |
| .card-hover:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
| } |
| .fade-in { |
| animation: fadeIn 0.5s ease-in-out; |
| } |
| @keyframes fadeIn { |
| from { opacity: 0; transform: translateY(10px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| .textarea-auto { |
| min-height: 120px; |
| resize: none; |
| } |
| .loading-dots:after { |
| content: '.'; |
| animation: dots 1.5s steps(5, end) infinite; |
| } |
| @keyframes dots { |
| 0%, 20% { content: '.'; } |
| 40% { content: '..'; } |
| 60% { content: '...'; } |
| 80%, 100% { content: ''; } |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 min-h-screen"> |
| |
| <header class="gradient-bg text-white shadow-lg"> |
| <div class="container mx-auto px-4 py-6"> |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center space-x-3"> |
| <i class="fas fa-robot text-3xl"></i> |
| <h1 class="text-2xl font-bold">Describe Anything Model</h1> |
| </div> |
| <div class="hidden md:flex space-x-4"> |
| <a href="#embedding" class="hover:text-blue-200 transition">Embedding</a> |
| <a href="#description" class="hover:text-blue-200 transition">Description</a> |
| <a href="#about" class="hover:text-blue-200 transition">About</a> |
| </div> |
| <button class="md:hidden text-xl" id="menu-toggle"> |
| <i class="fas fa-bars"></i> |
| </button> |
| </div> |
| </div> |
| </header> |
|
|
| |
| <div class="hidden bg-white shadow-md" id="mobile-menu"> |
| <div class="container mx-auto px-4 py-2 flex flex-col space-y-2"> |
| <a href="#embedding" class="py-2 hover:text-blue-600 transition">Embedding</a> |
| <a href="#description" class="py-2 hover:text-blue-600 transition">Description</a> |
| <a href="#about" class="py-2 hover:text-blue-600 transition">About</a> |
| </div> |
| </div> |
|
|
| |
| <section class="gradient-bg text-white py-12"> |
| <div class="container mx-auto px-4 text-center"> |
| <h2 class="text-4xl font-bold mb-4">AI-Powered Image Understanding</h2> |
| <p class="text-xl mb-8 max-w-2xl mx-auto">Generate detailed descriptions of any object in your images with our advanced computer vision model.</p> |
| <div class="flex justify-center space-x-4"> |
| <a href="#embedding" class="bg-white text-blue-600 px-6 py-3 rounded-lg font-medium hover:bg-blue-50 transition">Try Embedding</a> |
| <a href="#description" class="border-2 border-white px-6 py-3 rounded-lg font-medium hover:bg-white hover:bg-opacity-10 transition">Try Description</a> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <main class="container mx-auto px-4 py-12"> |
| |
| <section id="embedding" class="mb-16 fade-in"> |
| <div class="flex items-center mb-8"> |
| <div class="h-1 bg-blue-500 w-12 mr-4"></div> |
| <h2 class="text-3xl font-bold">Image Embedding Generator</h2> |
| </div> |
| |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> |
| <div class="bg-white rounded-xl shadow-md p-6 card-hover transition"> |
| <h3 class="text-xl font-semibold mb-4">Upload Your Image</h3> |
| <div class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center mb-4" id="drop-area"> |
| <i class="fas fa-cloud-upload-alt text-4xl text-blue-500 mb-3"></i> |
| <p class="mb-2">Drag & drop your image here</p> |
| <p class="text-sm text-gray-500 mb-4">or</p> |
| <input type="file" id="embedding-file" accept="image/*" class="hidden"> |
| <label for="embedding-file" class="bg-blue-500 text-white px-4 py-2 rounded-lg cursor-pointer hover:bg-blue-600 transition">Select Image</label> |
| </div> |
| <div class="flex justify-between items-center"> |
| <span class="text-sm text-gray-500" id="embedding-file-name">No file selected</span> |
| <button id="clear-embedding" class="text-red-500 text-sm hover:text-red-700 hidden">Clear</button> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-xl shadow-md p-6 card-hover transition"> |
| <h3 class="text-xl font-semibold mb-4">Generated Embedding</h3> |
| <div class="relative"> |
| <textarea id="embedding-result" class="w-full bg-gray-100 border border-gray-300 rounded-lg p-4 textarea-auto" placeholder="Your image embedding will appear here..." readonly></textarea> |
| <button id="copy-embedding" class="absolute top-2 right-2 bg-gray-200 hover:bg-gray-300 p-2 rounded-lg transition" title="Copy to clipboard"> |
| <i class="fas fa-copy"></i> |
| </button> |
| </div> |
| <button id="generate-embedding" class="mt-4 w-full bg-blue-500 text-white py-3 rounded-lg font-medium hover:bg-blue-600 transition flex items-center justify-center"> |
| <span id="embedding-button-text">Generate Embedding</span> |
| <span id="embedding-loading" class="hidden ml-2 loading-dots"></span> |
| </button> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section id="description" class="mb-16 fade-in"> |
| <div class="flex items-center mb-8"> |
| <div class="h-1 bg-blue-500 w-12 mr-4"></div> |
| <h2 class="text-3xl font-bold">Mask Description Generator</h2> |
| </div> |
| |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
| <div class="bg-white rounded-xl shadow-md p-6 card-hover transition"> |
| <h3 class="text-xl font-semibold mb-4">Upload Your Image</h3> |
| <div class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center mb-4" id="image-drop-area"> |
| <i class="fas fa-image text-4xl text-blue-500 mb-3"></i> |
| <p class="mb-2">Drag & drop your image here</p> |
| <p class="text-sm text-gray-500 mb-4">or</p> |
| <input type="file" id="image-file" accept="image/*" class="hidden"> |
| <label for="image-file" class="bg-blue-500 text-white px-4 py-2 rounded-lg cursor-pointer hover:bg-blue-600 transition">Select Image</label> |
| </div> |
| <div class="flex justify-between items-center"> |
| <span class="text-sm text-gray-500" id="image-file-name">No file selected</span> |
| <button id="clear-image" class="text-red-500 text-sm hover:text-red-700 hidden">Clear</button> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-xl shadow-md p-6 card-hover transition"> |
| <h3 class="text-xl font-semibold mb-4">Upload Your Mask</h3> |
| <div class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center mb-4" id="mask-drop-area"> |
| <i class="fas fa-mask text-4xl text-blue-500 mb-3"></i> |
| <p class="mb-2">Drag & drop your mask here</p> |
| <p class="text-sm text-gray-500 mb-4">or</p> |
| <input type="file" id="mask-file" accept="image/*" class="hidden"> |
| <label for="mask-file" class="bg-blue-500 text-white px-4 py-2 rounded-lg cursor-pointer hover:bg-blue-600 transition">Select Mask</label> |
| </div> |
| <div class="flex justify-between items-center"> |
| <span class="text-sm text-gray-500" id="mask-file-name">No file selected</span> |
| <button id="clear-mask" class="text-red-500 text-sm hover:text-red-700 hidden">Clear</button> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-xl shadow-md p-6 card-hover transition"> |
| <h3 class="text-xl font-semibold mb-4">Generate Description</h3> |
| <div class="mb-4"> |
| <label for="description-prompt" class="block text-sm font-medium text-gray-700 mb-1">Prompt (Optional)</label> |
| <input type="text" id="description-prompt" class="w-full border border-gray-300 rounded-lg p-3" placeholder="What would you like to know about this object?"> |
| </div> |
| <div class="relative mb-4"> |
| <label for="description-result" class="block text-sm font-medium text-gray-700 mb-1">Description</label> |
| <textarea id="description-result" class="w-full bg-gray-100 border border-gray-300 rounded-lg p-4 textarea-auto" placeholder="Your description will appear here..." readonly></textarea> |
| <button id="copy-description" class="absolute top-7 right-2 bg-gray-200 hover:bg-gray-300 p-2 rounded-lg transition" title="Copy to clipboard"> |
| <i class="fas fa-copy"></i> |
| </button> |
| </div> |
| <div class="flex space-x-3"> |
| <button id="generate-description" class="flex-1 bg-blue-500 text-white py-3 rounded-lg font-medium hover:bg-blue-600 transition flex items-center justify-center"> |
| <span id="description-button-text">Generate</span> |
| <span id="description-loading" class="hidden ml-2 loading-dots"></span> |
| </button> |
| <button id="generate-streaming" class="flex-1 bg-purple-500 text-white py-3 rounded-lg font-medium hover:bg-purple-600 transition flex items-center justify-center"> |
| <span id="streaming-button-text">Stream</span> |
| <span id="streaming-loading" class="hidden ml-2 loading-dots"></span> |
| </button> |
| </div> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section id="preview" class="mb-16 fade-in"> |
| <div class="flex items-center mb-8"> |
| <div class="h-1 bg-blue-500 w-12 mr-4"></div> |
| <h2 class="text-3xl font-bold">Image & Mask Preview</h2> |
| </div> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-8"> |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h3 class="text-xl font-semibold mb-4">Image Preview</h3> |
| <div class="border border-gray-200 rounded-lg overflow-hidden"> |
| <img id="image-preview" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300' viewBox='0 0 400 300' fill='%23f3f4f6'%3E%3Crect width='400' height='300'/%3E%3Ctext x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-family='Arial' font-size='16' fill='%239ca3af'%3ENo image selected%3C/text%3E%3C/svg%3E" alt="Image preview" class="w-full h-auto"> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h3 class="text-xl font-semibold mb-4">Mask Preview</h3> |
| <div class="border border-gray-200 rounded-lg overflow-hidden"> |
| <img id="mask-preview" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300' viewBox='0 0 400 300' fill='%23f3f4f6'%3E%3Crect width='400' height='300'/%3E%3Ctext x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-family='Arial' font-size='16' fill='%239ca3af'%3ENo mask selected%3C/text%3E%3C/svg%3E" alt="Mask preview" class="w-full h-auto"> |
| </div> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section id="about" class="fade-in"> |
| <div class="flex items-center mb-8"> |
| <div class="h-1 bg-blue-500 w-12 mr-4"></div> |
| <h2 class="text-3xl font-bold">About Describe Anything Model</h2> |
| </div> |
| |
| <div class="bg-white rounded-xl shadow-md p-8"> |
| <div class="prose max-w-none"> |
| <h3 class="text-2xl font-semibold mb-4">Advanced Image Understanding</h3> |
| <p class="mb-4">The Describe Anything Model (DAM) is a cutting-edge AI system that combines computer vision with natural language processing to provide detailed descriptions of objects in images.</p> |
| |
| <h4 class="text-xl font-semibold mt-6 mb-3">Key Features</h4> |
| <ul class="list-disc pl-6 mb-6 space-y-2"> |
| <li>Generate rich semantic embeddings for any image</li> |
| <li>Describe specific objects using segmentation masks</li> |
| <li>Answer questions about objects in images</li> |
| <li>Streaming output for real-time results</li> |
| </ul> |
| |
| <h4 class="text-xl font-semibold mt-6 mb-3">How It Works</h4> |
| <ol class="list-decimal pl-6 mb-6 space-y-2"> |
| <li>Upload an image to generate its embedding</li> |
| <li>Optionally upload a mask to focus on specific objects</li> |
| <li>Provide a prompt to guide the description</li> |
| <li>Get detailed, AI-generated descriptions</li> |
| </ol> |
| |
| <div class="bg-blue-50 border-l-4 border-blue-500 p-4 mt-6"> |
| <p class="text-blue-700"><strong>Note:</strong> This is a demonstration interface. For production use, consider implementing proper API endpoints and error handling.</p> |
| </div> |
| </div> |
| </div> |
| </section> |
| </main> |
|
|
| |
| <footer class="bg-gray-800 text-white py-8"> |
| <div class="container mx-auto px-4"> |
| <div class="flex flex-col md:flex-row justify-between items-center"> |
| <div class="mb-4 md:mb-0"> |
| <h3 class="text-xl font-bold mb-2">Describe Anything Model</h3> |
| <p class="text-gray-400">Advanced AI for image understanding</p> |
| </div> |
| <div class="flex space-x-6"> |
| <a href="#" class="text-gray-400 hover:text-white transition"><i class="fab fa-github text-xl"></i></a> |
| <a href="#" class="text-gray-400 hover:text-white transition"><i class="fab fa-twitter text-xl"></i></a> |
| <a href="#" class="text-gray-400 hover:text-white transition"><i class="fab fa-linkedin text-xl"></i></a> |
| </div> |
| </div> |
| <div class="border-t border-gray-700 mt-8 pt-8 text-center text-gray-400"> |
| <p>© 2023 Describe Anything Model. All rights reserved.</p> |
| </div> |
| </div> |
| </footer> |
|
|
| <script> |
| |
| document.getElementById('menu-toggle').addEventListener('click', function() { |
| const menu = document.getElementById('mobile-menu'); |
| menu.classList.toggle('hidden'); |
| }); |
| |
| |
| const embeddingFileInput = document.getElementById('embedding-file'); |
| const embeddingDropArea = document.getElementById('drop-area'); |
| const embeddingFileName = document.getElementById('embedding-file-name'); |
| const clearEmbeddingBtn = document.getElementById('clear-embedding'); |
| const generateEmbeddingBtn = document.getElementById('generate-embedding'); |
| const embeddingResult = document.getElementById('embedding-result'); |
| const copyEmbeddingBtn = document.getElementById('copy-embedding'); |
| const embeddingButtonText = document.getElementById('embedding-button-text'); |
| const embeddingLoading = document.getElementById('embedding-loading'); |
| |
| |
| const imageFileInput = document.getElementById('image-file'); |
| const imageDropArea = document.getElementById('image-drop-area'); |
| const imageFileName = document.getElementById('image-file-name'); |
| const clearImageBtn = document.getElementById('clear-image'); |
| const maskFileInput = document.getElementById('mask-file'); |
| const maskDropArea = document.getElementById('mask-drop-area'); |
| const maskFileName = document.getElementById('mask-file-name'); |
| const clearMaskBtn = document.getElementById('clear-mask'); |
| const generateDescriptionBtn = document.getElementById('generate-description'); |
| const generateStreamingBtn = document.getElementById('generate-streaming'); |
| const descriptionResult = document.getElementById('description-result'); |
| const copyDescriptionBtn = document.getElementById('copy-description'); |
| const descriptionPrompt = document.getElementById('description-prompt'); |
| const descriptionButtonText = document.getElementById('description-button-text'); |
| const descriptionLoading = document.getElementById('description-loading'); |
| const streamingButtonText = document.getElementById('streaming-button-text'); |
| const streamingLoading = document.getElementById('streaming-loading'); |
| const imagePreview = document.getElementById('image-preview'); |
| const maskPreview = document.getElementById('mask-preview'); |
| |
| |
| [embeddingDropArea, imageDropArea, maskDropArea].forEach(area => { |
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { |
| area.addEventListener(eventName, preventDefaults, false); |
| }); |
| }); |
| |
| function preventDefaults(e) { |
| e.preventDefault(); |
| e.stopPropagation(); |
| } |
| |
| |
| [embeddingDropArea, imageDropArea, maskDropArea].forEach(area => { |
| ['dragenter', 'dragover'].forEach(eventName => { |
| area.addEventListener(eventName, highlight, false); |
| }); |
| |
| ['dragleave', 'drop'].forEach(eventName => { |
| area.addEventListener(eventName, unhighlight, false); |
| }); |
| }); |
| |
| function highlight() { |
| this.classList.add('border-blue-500', 'bg-blue-50'); |
| } |
| |
| function unhighlight() { |
| this.classList.remove('border-blue-500', 'bg-blue-50'); |
| } |
| |
| |
| embeddingDropArea.addEventListener('drop', handleEmbeddingDrop, false); |
| imageDropArea.addEventListener('drop', handleImageDrop, false); |
| maskDropArea.addEventListener('drop', handleMaskDrop, false); |
| |
| function handleEmbeddingDrop(e) { |
| const dt = e.dataTransfer; |
| const files = dt.files; |
| if (files.length) { |
| handleEmbeddingFile(files[0]); |
| } |
| } |
| |
| function handleImageDrop(e) { |
| const dt = e.dataTransfer; |
| const files = dt.files; |
| if (files.length) { |
| handleImageFile(files[0]); |
| } |
| } |
| |
| function handleMaskDrop(e) { |
| const dt = e.dataTransfer; |
| const files = dt.files; |
| if (files.length) { |
| handleMaskFile(files[0]); |
| } |
| } |
| |
| |
| embeddingFileInput.addEventListener('change', function() { |
| if (this.files.length) { |
| handleEmbeddingFile(this.files[0]); |
| } |
| }); |
| |
| imageFileInput.addEventListener('change', function() { |
| if (this.files.length) { |
| handleImageFile(this.files[0]); |
| } |
| }); |
| |
| maskFileInput.addEventListener('change', function() { |
| if (this.files.length) { |
| handleMaskFile(this.files[0]); |
| } |
| }); |
| |
| function handleEmbeddingFile(file) { |
| if (!file.type.match('image.*')) { |
| alert('Please select an image file.'); |
| return; |
| } |
| |
| embeddingFileName.textContent = file.name; |
| clearEmbeddingBtn.classList.remove('hidden'); |
| |
| |
| } |
| |
| function handleImageFile(file) { |
| if (!file.type.match('image.*')) { |
| alert('Please select an image file.'); |
| return; |
| } |
| |
| imageFileName.textContent = file.name; |
| clearImageBtn.classList.remove('hidden'); |
| |
| |
| const reader = new FileReader(); |
| reader.onload = function(e) { |
| imagePreview.src = e.target.result; |
| }; |
| reader.readAsDataURL(file); |
| } |
| |
| function handleMaskFile(file) { |
| if (!file.type.match('image.*')) { |
| alert('Please select an image file.'); |
| return; |
| } |
| |
| maskFileName.textContent = file.name; |
| clearMaskBtn.classList.remove('hidden'); |
| |
| |
| const reader = new FileReader(); |
| reader.onload = function(e) { |
| maskPreview.src = e.target.result; |
| }; |
| reader.readAsDataURL(file); |
| } |
| |
| |
| clearEmbeddingBtn.addEventListener('click', function() { |
| embeddingFileInput.value = ''; |
| embeddingFileName.textContent = 'No file selected'; |
| this.classList.add('hidden'); |
| embeddingResult.value = ''; |
| }); |
| |
| clearImageBtn.addEventListener('click', function() { |
| imageFileInput.value = ''; |
| imageFileName.textContent = 'No file selected'; |
| this.classList.add('hidden'); |
| imagePreview.src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300' viewBox='0 0 400 300' fill='%23f3f4f6'%3E%3Crect width='400' height='300'/%3E%3Ctext x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-family='Arial' font-size='16' fill='%239ca3af'%3ENo image selected%3C/text%3E%3C/svg%3E"; |
| }); |
| |
| clearMaskBtn.addEventListener('click', function() { |
| maskFileInput.value = ''; |
| maskFileName.textContent = 'No file selected'; |
| this.classList.add('hidden'); |
| maskPreview.src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300' viewBox='0 0 400 300' fill='%23f3f4f6'%3E%3Crect width='400' height='300'/%3E%3Ctext x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-family='Arial' font-size='16' fill='%239ca3af'%3ENo mask selected%3C/text%3E%3C/svg%3E"; |
| }); |
| |
| |
| copyEmbeddingBtn.addEventListener('click', function() { |
| embeddingResult.select(); |
| document.execCommand('copy'); |
| |
| |
| const originalText = this.innerHTML; |
| this.innerHTML = '<i class="fas fa-check"></i>'; |
| setTimeout(() => { |
| this.innerHTML = originalText; |
| }, 2000); |
| }); |
| |
| copyDescriptionBtn.addEventListener('click', function() { |
| descriptionResult.select(); |
| document.execCommand('copy'); |
| |
| |
| const originalText = this.innerHTML; |
| this.innerHTML = '<i class="fas fa-check"></i>'; |
| setTimeout(() => { |
| this.innerHTML = originalText; |
| }, 2000); |
| }); |
| |
| |
| generateEmbeddingBtn.addEventListener('click', function() { |
| if (!embeddingFileInput.files.length) { |
| alert('Please select an image file first.'); |
| return; |
| } |
| |
| |
| embeddingButtonText.textContent = 'Processing'; |
| embeddingLoading.classList.remove('hidden'); |
| |
| setTimeout(() => { |
| |
| |
| embeddingResult.value = "This would be the base64 encoded embedding from the API response."; |
| |
| embeddingButtonText.textContent = 'Generate Embedding'; |
| embeddingLoading.classList.add('hidden'); |
| }, 2000); |
| }); |
| |
| generateDescriptionBtn.addEventListener('click', function() { |
| if (!imageFileInput.files.length || !maskFileInput.files.length) { |
| alert('Please select both an image and a mask file first.'); |
| return; |
| } |
| |
| |
| descriptionButtonText.textContent = 'Processing'; |
| descriptionLoading.classList.remove('hidden'); |
| descriptionResult.value = ''; |
| |
| setTimeout(() => { |
| |
| |
| const prompt = descriptionPrompt.value || "Describe the object in the mask"; |
| descriptionResult.value = `This is a detailed description of the object in the mask based on the prompt: "${prompt}".\n\nThe description would include specific details about the object's appearance, context, and any other relevant information the model can provide.`; |
| |
| descriptionButtonText.textContent = 'Generate'; |
| descriptionLoading.classList.add('hidden'); |
| }, 3000); |
| }); |
| |
| generateStreamingBtn.addEventListener('click', function() { |
| if (!imageFileInput.files.length || !maskFileInput.files.length) { |
| alert('Please select both an image and a mask file first.'); |
| return; |
| } |
| |
| |
| streamingButtonText.textContent = 'Streaming'; |
| streamingLoading.classList.remove('hidden'); |
| descriptionResult.value = ''; |
| |
| const prompt = descriptionPrompt.value || "Describe the object in the mask"; |
| const demoTexts = [ |
| "This is the first part of the description... ", |
| "The object appears to be a person standing in a park. ", |
| "They are wearing a blue jacket and holding a bag. ", |
| "The background shows trees and a clear sky. ", |
| "The lighting suggests it's late afternoon. ", |
| "This completes the description of the object." |
| ]; |
| |
| let i = 0; |
| const interval = setInterval(() => { |
| if (i < demoTexts.length) { |
| descriptionResult.value += demoTexts[i]; |
| i++; |
| } else { |
| clearInterval(interval); |
| streamingButtonText.textContent = 'Stream'; |
| streamingLoading.classList.add('hidden'); |
| } |
| }, 500); |
| }); |
| |
| |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { |
| anchor.addEventListener('click', function(e) { |
| e.preventDefault(); |
| |
| const targetId = this.getAttribute('href'); |
| if (targetId === '#') return; |
| |
| const targetElement = document.querySelector(targetId); |
| if (targetElement) { |
| targetElement.scrollIntoView({ |
| behavior: 'smooth' |
| }); |
| |
| |
| const mobileMenu = document.getElementById('mobile-menu'); |
| if (!mobileMenu.classList.contains('hidden')) { |
| mobileMenu.classList.add('hidden'); |
| } |
| } |
| }); |
| }); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Boobs00/ai-powered-image-understanding" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |