shailex/stable-diffusion-api
1
1<!DOCTYPE html>2<html lang="en">3 4<head>5 <meta charset="UTF-8">6 <meta name="viewport" content="width=device-width, initial-scale=1.0">7 <title>Stable Diffusion Image Generator</title>8 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">9 <style>10 body {11 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;12 background-color: #f8f9fa;13 padding-bottom: 40px;14 }15 16 .header {17 background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);18 color: white;19 padding: 2rem 0;20 margin-bottom: 2rem;21 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);22 }23 24 .form-container {25 background-color: white;26 border-radius: 10px;27 padding: 30px;28 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);29 margin-bottom: 2rem;30 }31 32 .image-gallery {33 display: grid;34 grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));35 gap: 20px;36 margin-top: 30px;37 }38 39 .image-card {40 background-color: white;41 border-radius: 10px;42 overflow: hidden;43 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);44 transition: transform 0.3s ease;45 }46 47 .image-card:hover {48 transform: translateY(-5px);49 }50 51 .image-container {52 position: relative;53 padding-top: 100%;54 /* 1:1 Aspect Ratio */55 overflow: hidden;56 }57 58 .generated-image {59 position: absolute;60 top: 0;61 left: 0;62 width: 100%;63 height: 100%;64 object-fit: contain;65 background-color: #f8f9fa;66 }67 68 .image-actions {69 padding: 15px;70 display: flex;71 justify-content: space-between;72 align-items: center;73 background-color: #f8f9fa;74 }75 76 .loading-spinner {77 display: none;78 text-align: center;79 margin: 20px 0;80 }81 82 .slider-container {83 margin-bottom: 20px;84 }85 86 .slider-value {87 font-weight: bold;88 margin-left: 10px;89 }90 91 footer {92 margin-top: 3rem;93 padding: 20px 0;94 background-color: #f1f1f1;95 text-align: center;96 }97 98 #status {99 display: none;100 margin-top: 20px;101 padding: 10px;102 border-radius: 5px;103 }104 105 .status-success {106 background-color: #d4edda;107 color: #155724;108 }109 110 .status-error {111 background-color: #f8d7da;112 color: #721c24;113 }114 115 .api-url-container {116 margin-bottom: 20px;117 padding: 10px;118 background-color: #e9ecef;119 border-radius: 5px;120 }121 </style>122</head>123 124<body>125 <div class="header text-center">126 <div class="container">127 <h1>Stable Diffusion Image Generator</h1>128 <p class="lead">Create stunning AI-generated images from text descriptions</p>129 </div>130 </div>131 132 <div class="container">133 <div class="form-container">134 <!-- Added API URL configuration -->135 <div class="api-url-container">136 <div class="mb-3">137 <label for="api-url" class="form-label">API URL:</label>138 <div class="input-group">139 <input type="text" class="form-control" id="api-url" value="http://localhost:7860/proxy-generate">140 <button class="btn btn-outline-secondary" type="button" id="test-connection">Test Connection</button>141 </div>142 <div class="form-text">If running locally, use localhost. If using HuggingFace, use their API URL.</div>143 </div>144 <div id="connection-status"></div>145 </div>146 147 <form id="generation-form">148 <div class="mb-4">149 <label for="prompt" class="form-label">Enter your prompt:</label>150 <textarea class="form-control" id="prompt" rows="3"151 placeholder="Describe the image you want to generate..." required></textarea>152 </div>153 154 <div class="row">155 <div class="col-md-4 mb-3">156 <label for="num-images" class="form-label">Number of Images:</label>157 <div class="slider-container d-flex align-items-center">158 <input type="range" class="form-range" min="1" max="4" step="1" value="2" id="num-images">159 <span class="slider-value" id="num-images-value">2</span>160 </div>161 </div>162 <div class="col-md-4 mb-3">163 <label for="steps" class="form-label">Inference Steps:</label>164 <div class="slider-container d-flex align-items-center">165 <input type="range" class="form-range" min="20" max="100" step="10" value="50" id="steps">166 <span class="slider-value" id="steps-value">50</span>167 </div>168 </div>169 <div class="col-md-4 mb-3">170 <label for="guidance" class="form-label">Guidance Scale:</label>171 <div class="slider-container d-flex align-items-center">172 <input type="range" class="form-range" min="1" max="20" step="0.5" value="7.5"173 id="guidance">174 <span class="slider-value" id="guidance-value">7.5</span>175 </div>176 </div>177 </div>178 179 <div class="d-grid">180 <button type="submit" class="btn btn-primary btn-lg">Generate Images</button>181 </div>182 </form>183 184 <div id="status"></div>185 186 <div class="loading-spinner" id="loading">187 <div class="spinner-border text-primary" role="status">188 <span class="visually-hidden">Loading...</span>189 </div>190 <p>Generating your images... This may take a minute.</p>191 </div>192 </div>193 194 <div class="image-gallery" id="image-gallery">195 <!-- Images will be displayed here -->196 </div>197 </div>198 199 <footer>200 <div class="container">201 <p>Powered by Stable Diffusion | Created by Shailesh Tagadghar</p>202 </div>203 </footer>204 205 <script>206 // Updated to use configurable API URL207 let API_URL = 'http://localhost:7860/proxy-generate';208 209 // Test connection button210 document.getElementById('test-connection').addEventListener('click', function() {211 const url = document.getElementById('api-url').value;212 const connectionStatus = document.getElementById('connection-status');213 214 connectionStatus.innerHTML = '<div class="alert alert-info">Testing connection...</div>';215 216 // Test the root endpoint of the API217 fetch(url.replace('/proxy-generate', '/'))218 .then(response => {219 if (response.ok) {220 return response.json();221 } else {222 throw new Error('Server returned an error');223 }224 })225 .then(data => {226 connectionStatus.innerHTML = `<div class="alert alert-success">Connection successful! Server running on ${data.device}</div>`;227 API_URL = document.getElementById('api-url').value;228 })229 .catch(error => {230 connectionStatus.innerHTML = '<div class="alert alert-danger">Connection failed. Please check the URL and make sure the server is running.</div>';231 console.error('Connection error:', error);232 });233 });234 235 // Update slider values236 document.getElementById('num-images').addEventListener('input', function () {237 document.getElementById('num-images-value').textContent = this.value;238 });239 240 document.getElementById('steps').addEventListener('input', function () {241 document.getElementById('steps-value').textContent = this.value;242 });243 244 document.getElementById('guidance').addEventListener('input', function () {245 document.getElementById('guidance-value').textContent = this.value;246 });247 248 // Form submission249 document.getElementById('generation-form').addEventListener('submit', function (e) {250 e.preventDefault();251 252 // Get values253 const prompt = document.getElementById('prompt').value;254 const numImages = document.getElementById('num-images').value;255 const steps = document.getElementById('steps').value;256 const guidance = document.getElementById('guidance').value;257 258 // Use the current API URL259 API_URL = document.getElementById('api-url').value;260 261 // Show loading spinner262 document.getElementById('loading').style.display = 'block';263 document.getElementById('status').style.display = 'none';264 265 // Send request266 fetch(API_URL, {267 method: 'POST',268 headers: {269 'Content-Type': 'application/json',270 },271 body: JSON.stringify({272 prompt: prompt,273 num_images: parseInt(numImages),274 steps: parseInt(steps),275 guidance: parseFloat(guidance)276 })277 })278 .then(response => {279 if (!response.ok) {280 throw new Error('Server returned an error: ' + response.status);281 }282 return response.json();283 })284 .then(data => {285 // Hide loading spinner286 document.getElementById('loading').style.display = 'none';287 288 if (data.error) {289 // Show error message290 const statusEl = document.getElementById('status');291 statusEl.className = 'status-error';292 statusEl.textContent = data.error;293 statusEl.style.display = 'block';294 } else {295 // Display images296 const gallery = document.getElementById('image-gallery');297 gallery.innerHTML = '';298 299 data.images.forEach((image, index) => {300 const card = document.createElement('div');301 card.className = 'image-card';302 303 card.innerHTML = `304 <div class="image-container">305 <img src="data:image/png;base64,${image.data}" class="generated-image" alt="Generated image ${index + 1}">306 </div>307 <div class="image-actions">308 <span>Image ${index + 1}</span>309 <a href="data:image/png;base64,${image.data}" class="btn btn-sm btn-outline-primary" download="generated_image_${index + 1}.png">Download</a>310 </div>311 `;312 313 gallery.appendChild(card);314 });315 316 // Show success message317 const statusEl = document.getElementById('status');318 statusEl.className = 'status-success';319 statusEl.textContent = 'Images generated successfully!';320 statusEl.style.display = 'block';321 }322 })323 .catch(error => {324 // Hide loading spinner325 document.getElementById('loading').style.display = 'none';326 327 // Show error message328 const statusEl = document.getElementById('status');329 statusEl.className = 'status-error';330 statusEl.textContent = 'An error occurred: ' + error.message;331 statusEl.style.display = 'block';332 console.error('Error:', error);333 });334 });335 </script>336 337 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>338</body>339 340</html>