|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const guidanceSlider = document.getElementById('guidance-scale'); |
|
|
const guidanceValue = document.getElementById('guidance-value'); |
|
|
const stepsSlider = document.getElementById('steps'); |
|
|
const stepsValue = document.getElementById('steps-value'); |
|
|
const seedSlider = document.getElementById('seed'); |
|
|
const seedValue = document.getElementById('seed-value'); |
|
|
const generateBtn = document.getElementById('generate-btn'); |
|
|
const imagePreview = document.getElementById('image-preview'); |
|
|
|
|
|
guidanceSlider.addEventListener('input', () => { |
|
|
guidanceValue.textContent = guidanceSlider.value; |
|
|
}); |
|
|
|
|
|
stepsSlider.addEventListener('input', () => { |
|
|
stepsValue.textContent = stepsSlider.value; |
|
|
}); |
|
|
|
|
|
seedSlider.addEventListener('input', () => { |
|
|
seedValue.textContent = seedSlider.value === "-1" ? "Random" : seedSlider.value; |
|
|
}); |
|
|
|
|
|
|
|
|
generateBtn.addEventListener('click', async function() { |
|
|
const prompt = document.getElementById('prompt-input').value; |
|
|
if (!prompt.trim()) { |
|
|
alert('Please enter a prompt first!'); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
generateBtn.disabled = true; |
|
|
generateBtn.innerHTML = '<i data-feather="loader" class="spinner mr-2"></i> Generating...'; |
|
|
feather.replace(); |
|
|
|
|
|
imagePreview.classList.add('loading'); |
|
|
imagePreview.innerHTML = ` |
|
|
<div class="absolute inset-0 flex items-center justify-center z-20"> |
|
|
<div class="text-center p-6"> |
|
|
<i data-feather="loader" class="spinner w-12 h-12 mx-auto text-white mb-4"></i> |
|
|
<p class="text-white">Creating your masterpiece...</p> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
feather.replace(); |
|
|
try { |
|
|
const prompt = document.getElementById('prompt-input').value; |
|
|
const negativePrompt = document.getElementById('negative-prompt').value; |
|
|
const model = document.getElementById('model-select').value; |
|
|
const size = document.getElementById('size-select').value; |
|
|
const guidanceScale = parseFloat(guidanceSlider.value); |
|
|
const steps = parseInt(stepsSlider.value); |
|
|
const seed = seedSlider.value === "-1" ? Math.floor(Math.random() * 1000000) : parseInt(seedSlider.value); |
|
|
|
|
|
|
|
|
const response = await fetch('https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0', { |
|
|
method: 'POST', |
|
|
headers: { |
|
|
'Authorization': 'Bearer YOUR_HUGGINGFACE_API_KEY', |
|
|
'Content-Type': 'application/json' |
|
|
}, |
|
|
body: JSON.stringify({ |
|
|
inputs: prompt, |
|
|
parameters: { |
|
|
negative_prompt: negativePrompt, |
|
|
guidance_scale: guidanceScale, |
|
|
num_inference_steps: steps, |
|
|
width: parseInt(size.split('x')[0]), |
|
|
height: parseInt(size.split('x')[1]), |
|
|
seed: seed |
|
|
} |
|
|
}) |
|
|
}); |
|
|
|
|
|
if (!response.ok) { |
|
|
throw new Error(`API request failed with status ${response.status}`); |
|
|
} |
|
|
|
|
|
const imageBlob = await response.blob(); |
|
|
const imageUrl = URL.createObjectURL(imageBlob); |
|
|
|
|
|
|
|
|
imagePreview.classList.remove('loading'); |
|
|
imagePreview.innerHTML = `<img src="${imageUrl}" alt="Generated image" class="generated-image">`; |
|
|
|
|
|
|
|
|
const galleryGrid = document.getElementById('gallery-grid'); |
|
|
const galleryItem = document.createElement('div'); |
|
|
galleryItem.className = 'bg-gray-100 dark:bg-gray-700 rounded-lg aspect-square overflow-hidden'; |
|
|
galleryItem.innerHTML = `<img src="${imageUrl}" alt="Gallery item" class="w-full h-full object-cover">`; |
|
|
galleryGrid.insertBefore(galleryItem, galleryGrid.firstChild); |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Error generating image:', error); |
|
|
imagePreview.classList.remove('loading'); |
|
|
imagePreview.innerHTML = ` |
|
|
<div class="text-center p-6"> |
|
|
<i data-feather="alert-circle" class="w-12 h-12 mx-auto text-red-500 mb-4"></i> |
|
|
<p class="text-red-500">Error generating image: ${error.message}</p> |
|
|
</div> |
|
|
`; |
|
|
galleryGrid.insertBefore(galleryItem, galleryGrid.firstChild); |
|
|
|
|
|
|
|
|
generateBtn.disabled = false; |
|
|
generateBtn.innerHTML = '<i data-feather="sparkles" class="mr-2"></i> Generate Image'; |
|
|
feather.replace(); |
|
|
}); |
|
|
|
|
|
|
|
|
const themeToggleBtn = document.querySelector('.theme-toggle-btn'); |
|
|
if (themeToggleBtn) { |
|
|
themeToggleBtn.addEventListener('click', () => { |
|
|
document.documentElement.classList.toggle('dark'); |
|
|
localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
if (localStorage.getItem('theme') === 'dark' || (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { |
|
|
document.documentElement.classList.add('dark'); |
|
|
} else { |
|
|
document.documentElement.classList.remove('dark'); |
|
|
} |
|
|
}); |