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();
});