Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>AI Image Upscaler API Test</title> | |
| <style> | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| max-width: 800px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| background: #f5f5f5; | |
| } | |
| .container { | |
| background: white; | |
| padding: 30px; | |
| border-radius: 12px; | |
| box-shadow: 0 2px 10px rgba(0,0,0,0.1); | |
| } | |
| h1 { | |
| color: #333; | |
| text-align: center; | |
| margin-bottom: 30px; | |
| } | |
| .form-group { | |
| margin-bottom: 20px; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 5px; | |
| font-weight: 600; | |
| color: #555; | |
| } | |
| input, select { | |
| width: 100%; | |
| padding: 10px; | |
| border: 2px solid #ddd; | |
| border-radius: 6px; | |
| font-size: 16px; | |
| box-sizing: border-box; | |
| } | |
| input:focus, select:focus { | |
| outline: none; | |
| border-color: #007bff; | |
| } | |
| button { | |
| background: #007bff; | |
| color: white; | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: 6px; | |
| font-size: 16px; | |
| cursor: pointer; | |
| width: 100%; | |
| margin-top: 10px; | |
| } | |
| button:hover { | |
| background: #0056b3; | |
| } | |
| button:disabled { | |
| background: #ccc; | |
| cursor: not-allowed; | |
| } | |
| .result { | |
| margin-top: 30px; | |
| padding: 20px; | |
| background: #f8f9fa; | |
| border-radius: 6px; | |
| border-left: 4px solid #007bff; | |
| } | |
| .error { | |
| background: #f8d7da; | |
| border-left-color: #dc3545; | |
| color: #721c24; | |
| } | |
| .success { | |
| background: #d4edda; | |
| border-left-color: #28a745; | |
| color: #155724; | |
| } | |
| .image-container { | |
| display: flex; | |
| gap: 20px; | |
| margin-top: 20px; | |
| flex-wrap: wrap; | |
| } | |
| .image-box { | |
| flex: 1; | |
| min-width: 300px; | |
| } | |
| .image-box h3 { | |
| margin-top: 0; | |
| color: #555; | |
| } | |
| .image-box img { | |
| max-width: 100%; | |
| height: auto; | |
| border: 2px solid #ddd; | |
| border-radius: 6px; | |
| } | |
| .metadata { | |
| background: #e9ecef; | |
| padding: 15px; | |
| border-radius: 6px; | |
| margin-top: 15px; | |
| font-family: monospace; | |
| font-size: 14px; | |
| } | |
| .loading { | |
| text-align: center; | |
| padding: 20px; | |
| } | |
| .spinner { | |
| border: 4px solid #f3f3f3; | |
| border-top: 4px solid #007bff; | |
| border-radius: 50%; | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| margin: 0 auto 10px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>🚀 AI Image Upscaler API Test</h1> | |
| <form id="upscaleForm"> | |
| <div class="form-group"> | |
| <label for="imageFile">Select Image:</label> | |
| <input type="file" id="imageFile" accept="image/*" required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="scale">Scale Factor:</label> | |
| <select id="scale"> | |
| <option value="2">2x</option> | |
| <option value="3">3x</option> | |
| <option value="4">4x</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="modelType">AI Model:</label> | |
| <select id="modelType"> | |
| <option value="esrgan-slim">ESRGAN Slim (Fast)</option> | |
| <option value="esrgan-medium">ESRGAN Medium (Balanced)</option> | |
| <option value="esrgan-thick">ESRGAN Thick (Best Quality)</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="patchSize">Patch Size:</label> | |
| <select id="patchSize"> | |
| <option value="64">64</option> | |
| <option value="96">96</option> | |
| <option value="128" selected>128</option> | |
| <option value="160">160</option> | |
| <option value="192">192</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="padding">Padding:</label> | |
| <select id="padding"> | |
| <option value="0">0</option> | |
| <option value="4">4</option> | |
| <option value="8" selected>8</option> | |
| <option value="12">12</option> | |
| <option value="16">16</option> | |
| </select> | |
| </div> | |
| <button type="submit" id="submitBtn">Upscale Image</button> | |
| </form> | |
| <div id="result"></div> | |
| </div> | |
| <script> | |
| document.getElementById('upscaleForm').addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| const fileInput = document.getElementById('imageFile'); | |
| const scale = document.getElementById('scale').value; | |
| const modelType = document.getElementById('modelType').value; | |
| const patchSize = document.getElementById('patchSize').value; | |
| const padding = document.getElementById('padding').value; | |
| const submitBtn = document.getElementById('submitBtn'); | |
| const resultDiv = document.getElementById('result'); | |
| if (!fileInput.files[0]) { | |
| alert('Please select an image file'); | |
| return; | |
| } | |
| // Show loading state | |
| submitBtn.disabled = true; | |
| submitBtn.textContent = 'Processing...'; | |
| resultDiv.innerHTML = ` | |
| <div class="loading"> | |
| <div class="spinner"></div> | |
| <p>Upscaling image with ${scale}x scale using ${modelType} model...</p> | |
| </div> | |
| `; | |
| try { | |
| const formData = new FormData(); | |
| formData.append('image', fileInput.files[0]); | |
| formData.append('scale', scale); | |
| formData.append('modelType', modelType); | |
| formData.append('patchSize', patchSize); | |
| formData.append('padding', padding); | |
| const startTime = Date.now(); | |
| const response = await fetch('/upscale', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const result = await response.json(); | |
| const totalTime = Date.now() - startTime; | |
| if (result.success) { | |
| // Create original image URL | |
| const originalImageUrl = URL.createObjectURL(fileInput.files[0]); | |
| resultDiv.innerHTML = ` | |
| <div class="result success"> | |
| <h3>✅ Upscaling Successful!</h3> | |
| <div class="image-container"> | |
| <div class="image-box"> | |
| <h3>Original Image</h3> | |
| <img src="${originalImageUrl}" alt="Original"> | |
| </div> | |
| <div class="image-box"> | |
| <h3>Upscaled Image (${result.metadata.scale}x)</h3> | |
| <img src="${result.result}" alt="Upscaled"> | |
| <a href="${result.result}" download="upscaled-${result.metadata.scale}x.png" | |
| style="display: inline-block; margin-top: 10px; padding: 8px 16px; background: #007bff; color: white; text-decoration: none; border-radius: 4px;"> | |
| Download Upscaled Image | |
| </a> | |
| </div> | |
| </div> | |
| <div class="metadata"> | |
| <strong>Processing Details:</strong><br> | |
| Scale: ${result.metadata.scale}x<br> | |
| Model: ${result.metadata.modelType}<br> | |
| Patch Size: ${result.metadata.patchSize}<br> | |
| Padding: ${result.metadata.padding}<br> | |
| Backend: ${result.metadata.backend}<br> | |
| Server Processing Time: ${result.metadata.processingTime}ms<br> | |
| Total Time: ${totalTime}ms | |
| </div> | |
| </div> | |
| `; | |
| } else { | |
| throw new Error(result.error || 'Unknown error'); | |
| } | |
| } catch (error) { | |
| resultDiv.innerHTML = ` | |
| <div class="result error"> | |
| <h3>❌ Error</h3> | |
| <p><strong>Failed to upscale image:</strong> ${error.message}</p> | |
| </div> | |
| `; | |
| } finally { | |
| submitBtn.disabled = false; | |
| submitBtn.textContent = 'Upscale Image'; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |