File size: 7,342 Bytes
5d90d05 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
// HuggingFace API Configuration
const HF_API_KEY = 'YOUR_HF_API_KEY';
const SFW_MODELS = {
'Stable Diffusion XL': 'stabilityai/stable-diffusion-xl-base-1.0',
'DreamShaper XL': 'lykon/dreamshaper-xl',
'Anime XL': 'cagliostrolab/animagine-xl-3.0',
'Cyberpunk Anime': 'DGSpitzer/Cyberpunk-Anime-Diffusion',
'Realistic Vision': 'SG161222/Realistic_Vision_V5.1',
'Juggernaut XL': 'stabilityai/stable-diffusion-xl-base-1.0',
'Epic Realism': 'epicrealism/epicrealism-natural-sin',
'Pixel Art': 'nerijs/pixel-art-xl'
};
const NSFW_MODELS = {
'Erotica XL': 'gsdf/Counterfeit-V3.0',
'Hentai XL': 'nitrosocke/henmixReal',
'Adult XL': 'gsdf/Erotica',
'NSFW Anime': 'cagliostro/hentai-diffusion',
'Lewd Realism': 'gsdf/lewd-diffusion',
'Boudoir': 'gsdf/boudoir-diffusion',
'Kinky Art': 'gsdf/kinky-diffusion'
};
let currentModel = SFW_MODELS['Stable Diffusion XL'];
let isNSFW = false;
// DOM Elements
const promptInput = document.querySelector('textarea');
const styleSelect = document.querySelector('select:nth-of-type(1)');
const modelSelect = document.querySelector('select:nth-of-type(2)');
const generateBtn = document.querySelector('button');
const previewBox = document.querySelector('.aspect-square');
const gallerySection = document.getElementById('gallery');
const nsfwToggle = document.createElement('div');
// Initialize NSFW Toggle
function initNSFWToggle() {
nsfwToggle.className = 'flex items-center gap-2 mb-4';
nsfwToggle.innerHTML = `
<span class="text-sm font-medium">Content Filter</span>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" class="sr-only peer" ${isNSFW ? 'checked' : ''}>
<div class="w-11 h-6 bg-gray-700 rounded-full peer peer-checked:bg-primary-500 peer-focus:ring-2 peer-focus:ring-primary-500">
<div class="absolute top-0.5 left-[2px] bg-white w-5 h-5 rounded-full transition-transform peer-checked:translate-x-5"></div>
</div>
<span class="ml-2 text-sm">${isNSFW ? 'NSFW' : 'SFW'}</span>
</label>
`;
document.querySelector('#generate .space-y-4').prepend(nsfwToggle);
nsfwToggle.querySelector('input').addEventListener('change', toggleNSFW);
}
// Toggle NSFW/SFW mode
function toggleNSFW(e) {
isNSFW = e.target.checked;
updateModelOptions();
nsfwToggle.querySelector('span:last-child').textContent = isNSFW ? 'NSFW' : 'SFW';
}
// Update model options based on SFW/NSFW mode
function updateModelOptions() {
modelSelect.innerHTML = '';
const models = isNSFW ? NSFW_MODELS : SFW_MODELS;
for (const [name, modelId] of Object.entries(models)) {
const option = document.createElement('option');
option.value = modelId;
option.textContent = name;
if (modelId === currentModel) option.selected = true;
modelSelect.appendChild(option);
}
}
// Enhanced image generation with error handling and model status checks
async function generateImage() {
const prompt = promptInput.value.trim();
if (!prompt) {
showToast('Please enter a prompt', 'error');
return;
}
generateBtn.disabled = true;
generateBtn.innerHTML = '<i data-feather="loader" class="animate-spin"></i> Weaving Pixels...';
feather.replace();
try {
// First check if model is loaded
const modelStatus = await fetch(`https://api-inference.huggingface.co/status/${currentModel}`, {
headers: { 'Authorization': `Bearer ${HF_API_KEY}` }
});
if (!modelStatus.ok) throw new Error('Model status check failed');
const statusData = await modelStatus.json();
if (statusData.loaded !== true) {
showToast('Model is loading, please wait...', 'warning');
return;
}
// Generate image
const response = await fetch(`https://api-inference.huggingface.co/models/${currentModel}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${HF_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
inputs: prompt,
parameters: {
width: 1024,
height: 1024,
num_inference_steps: 50,
guidance_scale: 7.5
},
options: { wait_for_model: true }
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Generation failed');
}
const imageBlob = await response.blob();
const imageUrl = URL.createObjectURL(imageBlob);
// Update preview
previewBox.innerHTML = `
<div class="relative w-full h-full">
<img src="${imageUrl}" alt="Generated image" class="w-full h-full object-cover rounded-lg">
<div class="absolute bottom-0 left-0 right-0 bg-black/70 text-white p-2 text-xs">
${prompt.substring(0, 100)}${prompt.length > 100 ? '...' : ''}
</div>
</div>
`;
// Add to gallery
addToGallery(imageUrl, prompt);
showToast('Image generated successfully!', 'success');
} catch (error) {
console.error('Error:', error);
showToast(error.message || 'Generation failed. Please try again.', 'error');
} finally {
generateBtn.disabled = false;
generateBtn.innerHTML = '<i data-feather="zap"></i> Generate Magic';
feather.replace();
}
}
// Show toast notification
function showToast(message, type = 'info') {
const toast = document.createElement('div');
toast.className = `fixed bottom-4 right-4 px-4 py-2 rounded-lg shadow-lg text-white ${
type === 'error' ? 'bg-red-500' :
type === 'success' ? 'bg-green-500' :
type === 'warning' ? 'bg-yellow-500' : 'bg-primary-500'
}`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.add('opacity-0', 'transition-opacity', 'duration-300');
setTimeout(() => toast.remove(), 300);
}, 3000);
}
// Add generated image to gallery
function addToGallery(imageUrl, prompt) {
const galleryItem = document.createElement('div');
galleryItem.className = 'relative group rounded-lg overflow-hidden';
galleryItem.innerHTML = `
<img src="${imageUrl}" alt="${prompt}" class="w-full h-48 object-cover rounded-lg hover:scale-105 transition-transform cursor-pointer">
<div class="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center p-4">
<p class="text-white text-sm text-center">${prompt}</p>
</div>
`;
gallerySection.querySelector('.grid').prepend(galleryItem);
}
// Initialize
document.addEventListener('DOMContentLoaded', () => {
initNSFWToggle();
updateModelOptions();
// Event listeners
generateBtn.addEventListener('click', generateImage);
modelSelect.addEventListener('change', (e) => {
currentModel = e.target.value;
});
// Load feather icons
feather.replace();
});
|