Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Professional Portrait Creator | Qwen Image Edit</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; | |
| } | |
| :root { | |
| --primary: #2563eb; | |
| --primary-dark: #1d4ed8; | |
| --secondary: #64748b; | |
| --accent: #f59e0b; | |
| --light: #f8fafc; | |
| --dark: #1e293b; | |
| --success: #10b981; | |
| --shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); | |
| } | |
| body { | |
| background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); | |
| color: var(--dark); | |
| line-height: 1.6; | |
| min-height: 100vh; | |
| padding: 1rem; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| } | |
| header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 1.5rem 0; | |
| margin-bottom: 2rem; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| color: var(--primary); | |
| } | |
| .logo i { | |
| font-size: 1.75rem; | |
| } | |
| .built-with { | |
| font-size: 0.875rem; | |
| color: var(--secondary); | |
| } | |
| .built-with a { | |
| color: var(--primary); | |
| text-decoration: none; | |
| transition: color 0.3s; | |
| } | |
| .built-with a:hover { | |
| color: var(--primary-dark); | |
| text-decoration: underline; | |
| } | |
| main { | |
| display: grid; | |
| grid-template-columns: 1fr; | |
| gap: 2rem; | |
| } | |
| @media (min-width: 768px) { | |
| main { | |
| grid-template-columns: 1fr 1fr; | |
| } | |
| } | |
| .card { | |
| background: white; | |
| border-radius: 1rem; | |
| padding: 2rem; | |
| box-shadow: var(--shadow); | |
| transition: transform 0.3s, box-shadow 0.3s; | |
| } | |
| .card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.15); | |
| } | |
| .card-title { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| margin-bottom: 1rem; | |
| color: var(--primary); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .upload-area { | |
| border: 2px dashed #cbd5e1; | |
| border-radius: 0.75rem; | |
| padding: 3rem 1.5rem; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| margin-bottom: 1.5rem; | |
| background: #f8fafc; | |
| } | |
| .upload-area:hover { | |
| border-color: var(--primary); | |
| background: #f0f9ff; | |
| } | |
| .upload-area.active { | |
| border-color: var(--primary); | |
| background: #dbeafe; | |
| } | |
| .upload-icon { | |
| font-size: 3rem; | |
| color: var(--secondary); | |
| margin-bottom: 1rem; | |
| } | |
| .upload-text { | |
| color: var(--secondary); | |
| margin-bottom: 0.5rem; | |
| } | |
| .upload-button { | |
| background: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 0.75rem 1.5rem; | |
| border-radius: 0.5rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: background 0.3s; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .upload-button:hover { | |
| background: var(--primary-dark); | |
| } | |
| .preview-container { | |
| margin-top: 1.5rem; | |
| display: none; | |
| } | |
| .preview-title { | |
| font-size: 1rem; | |
| font-weight: 500; | |
| margin-bottom: 0.5rem; | |
| color: var(--secondary); | |
| } | |
| .preview-image { | |
| width: 100%; | |
| max-width: 300px; | |
| border-radius: 0.5rem; | |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); | |
| } | |
| .options { | |
| margin-top: 1.5rem; | |
| } | |
| .option-group { | |
| margin-bottom: 1.5rem; | |
| } | |
| .option-label { | |
| display: block; | |
| font-weight: 500; | |
| margin-bottom: 0.5rem; | |
| color: var(--dark); | |
| } | |
| .slider-container { | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| } | |
| .slider { | |
| flex: 1; | |
| -webkit-appearance: none; | |
| width: 100%; | |
| height: 8px; | |
| border-radius: 4px; | |
| background: #e2e8f0; | |
| outline: none; | |
| } | |
| .slider::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| appearance: none; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| background: var(--primary); | |
| cursor: pointer; | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); | |
| } | |
| .slider-value { | |
| font-weight: 600; | |
| color: var(--primary); | |
| min-width: 40px; | |
| text-align: center; | |
| } | |
| .button-group { | |
| display: flex; | |
| gap: 1rem; | |
| margin-top: 2rem; | |
| } | |
| .btn { | |
| padding: 0.875rem 1.5rem; | |
| border-radius: 0.5rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| flex: 1; | |
| justify-content: center; | |
| } | |
| .btn-primary { | |
| background: var(--primary); | |
| color: white; | |
| border: none; | |
| } | |
| .btn-primary:hover { | |
| background: var(--primary-dark); | |
| } | |
| .btn-secondary { | |
| background: white; | |
| color: var(--primary); | |
| border: 1px solid var(--primary); | |
| } | |
| .btn-secondary:hover { | |
| background: #f0f9ff; | |
| } | |
| .result-container { | |
| display: none; | |
| text-align: center; | |
| } | |
| .result-title { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| margin-bottom: 1rem; | |
| color: var(--success); | |
| } | |
| .result-image { | |
| width: 100%; | |
| max-width: 400px; | |
| border-radius: 0.75rem; | |
| box-shadow: var(--shadow); | |
| margin-bottom: 1.5rem; | |
| } | |
| .loading { | |
| display: none; | |
| text-align: center; | |
| padding: 2rem; | |
| } | |
| .loading-spinner { | |
| width: 50px; | |
| height: 50px; | |
| border: 5px solid #e2e8f0; | |
| border-top: 5px solid var(--primary); | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin: 0 auto 1rem; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .feature-list { | |
| list-style: none; | |
| margin-top: 1.5rem; | |
| } | |
| .feature-list li { | |
| padding: 0.5rem 0; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| } | |
| .feature-list i { | |
| color: var(--success); | |
| } | |
| footer { | |
| text-align: center; | |
| margin-top: 3rem; | |
| padding: 1.5rem 0; | |
| color: var(--secondary); | |
| font-size: 0.875rem; | |
| border-top: 1px solid #e2e8f0; | |
| } | |
| .notification { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| padding: 1rem 1.5rem; | |
| background: var(--success); | |
| color: white; | |
| border-radius: 0.5rem; | |
| box-shadow: var(--shadow); | |
| display: none; | |
| z-index: 1000; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <div class="logo"> | |
| <i class="fas fa-camera-retro"></i> | |
| <span>Professional Portrait Creator</span> | |
| </div> | |
| <div class="built-with"> | |
| Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a> | |
| </div> | |
| </header> | |
| <main> | |
| <div class="card"> | |
| <h2 class="card-title"><i class="fas fa-upload"></i> Upload Your Photo</h2> | |
| <div class="upload-area" id="uploadArea"> | |
| <i class="fas fa-cloud-upload-alt upload-icon"></i> | |
| <p class="upload-text">Drag & drop your iPhone photo here</p> | |
| <p class="upload-text">or</p> | |
| <button class="upload-button" id="uploadButton"> | |
| <i class="fas fa-folder-open"></i> Browse Files | |
| </button> | |
| <input type="file" id="fileInput" accept="image/*" style="display: none;"> | |
| </div> | |
| <div class="preview-container" id="previewContainer"> | |
| <p class="preview-title">Photo Preview:</p> | |
| <img id="previewImage" class="preview-image" src="" alt="Preview"> | |
| </div> | |
| <div class="options"> | |
| <div class="option-group"> | |
| <label class="option-label">Background Blur (Bokeh)</label> | |
| <div class="slider-container"> | |
| <input type="range" min="1" max="10" value="7" class="slider" id="blurSlider"> | |
| <span class="slider-value" id="blurValue">7</span> | |
| </div> | |
| </div> | |
| <div class="option-group"> | |
| <label class="option-label">Professional Enhancement</label> | |
| <div class="slider-container"> | |
| <input type="range" min="1" max="10" value="8" class="slider" id="enhanceSlider"> | |
| <span class="slider-value" id="enhanceValue">8</span> | |
| </div> | |
| </div> | |
| <div class="option-group"> | |
| <label class="option-label">Background Style</label> | |
| <select id="backgroundStyle" class="slider" style="width: 100%; padding: 0.5rem; border-radius: 0.5rem; border: 1px solid #cbd5e1;"> | |
| <option value="modern">Modern Office</option> | |
| <option value="corporate">Corporate Environment</option> | |
| <option value="executive">Executive Suite</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="button-group"> | |
| <button class="btn btn-primary" id="generateBtn"> | |
| <i class="fas fa-magic"></i> Generate Portrait | |
| </button> | |
| <button class="btn btn-secondary" id="resetBtn"> | |
| <i class="fas fa-redo"></i> Reset | |
| </button> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h2 class="card-title"><i class="fas fa-image"></i> Your Professional Portrait</h2> | |
| <div class="loading" id="loading"> | |
| <div class="loading-spinner"></div> | |
| <p>Creating your professional portrait with Qwen Image Edit 2509...</p> | |
| </div> | |
| <div class="result-container" id="resultContainer"> | |
| <h3 class="result-title">Your Enhanced Business Portrait</h3> | |
| <img id="resultImage" class="result-image" src="" alt="Enhanced Portrait"> | |
| <div class="button-group"> | |
| <button class="btn btn-primary" id="downloadBtn"> | |
| <i class="fas fa-download"></i> Download Portrait | |
| </button> | |
| </div> | |
| </div> | |
| <div id="placeholderResult"> | |
| <p style="text-align: center; color: var(--secondary); padding: 4rem 2rem;"> | |
| <i class="fas fa-user-tie" style="font-size: 4rem; margin-bottom: 1rem; color: #e2e8f0;"></i><br> | |
| Your enhanced business portrait will appear here after processing. | |
| </p> | |
| <h3 class="card-title" style="margin-top: 2rem;"><i class="fas fa-star"></i> Features</h3> | |
| <ul class="feature-list"> | |
| <li><i class="fas fa-check-circle"></i> High-quality portrait enhancement</li> | |
| <li><i class="fas fa-check-circle"></i> Professional bokeh office background</li> | |
| <li><i class="fas fa-check-circle"></i> Lighting and color correction</li> | |
| <li><i class="fas fa-check-circle"></i> Professional attire enhancement</li> | |
| <li><i class="fas fa-check-circle"></i> Optimized for LinkedIn & professional profiles</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </main> | |
| <footer> | |
| <p>Professional Portrait Creator © 2023 | Powered by Qwen Image Edit 2509</p> | |
| </footer> | |
| </div> | |
| <div class="notification" id="notification"> | |
| <i class="fas fa-check-circle"></i> Portrait successfully generated! | |
| </div> | |
| <script> | |
| // DOM Elements | |
| const uploadArea = document.getElementById('uploadArea'); | |
| const uploadButton = document.getElementById('uploadButton'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const previewContainer = document.getElementById('previewContainer'); | |
| const previewImage = document.getElementById('previewImage'); | |
| const blurSlider = document.getElementById('blurSlider'); | |
| const blurValue = document.getElementById('blurValue'); | |
| const enhanceSlider = document.getElementById('enhanceSlider'); | |
| const enhanceValue = document.getElementById('enhanceValue'); | |
| const generateBtn = document.getElementById('generateBtn'); | |
| const resetBtn = document.getElementById('resetBtn'); | |
| const loading = document.getElementById('loading'); | |
| const resultContainer = document.getElementById('resultContainer'); | |
| const placeholderResult = document.getElementById('placeholderResult'); | |
| const resultImage = document.getElementById('resultImage'); | |
| const downloadBtn = document.getElementById('downloadBtn'); | |
| const notification = document.getElementById('notification'); | |
| // Event Listeners | |
| uploadButton.addEventListener('click', () => { | |
| fileInput.click(); | |
| }); | |
| uploadArea.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| uploadArea.classList.add('active'); | |
| }); | |
| uploadArea.addEventListener('dragleave', () => { | |
| uploadArea.classList.remove('active'); | |
| }); | |
| uploadArea.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| uploadArea.classList.remove('active'); | |
| if (e.dataTransfer.files.length) { | |
| handleFile(e.dataTransfer.files[0]); | |
| } | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| if (e.target.files.length) { | |
| handleFile(e.target.files[0]); | |
| } | |
| }); | |
| blurSlider.addEventListener('input', () => { | |
| blurValue.textContent = blurSlider.value; | |
| }); | |
| enhanceSlider.addEventListener('input', () => { | |
| enhanceValue.textContent = enhanceSlider.value; | |
| }); | |
| generateBtn.addEventListener('click', generatePortrait); | |
| resetBtn.addEventListener('click', resetForm); | |
| downloadBtn.addEventListener('click', downloadPortrait); | |
| // Functions | |
| function handleFile(file) { | |
| if (!file.type.match('image.*')) { | |
| alert('Please select an image file.'); | |
| return; | |
| } | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| previewImage.src = e.target.result; | |
| previewContainer.style.display = 'block'; | |
| generateBtn.disabled = false; | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| function generatePortrait() { | |
| if (!previewImage.src) { | |
| alert('Please upload a photo first.'); | |
| return; | |
| } | |
| // Show loading state | |
| loading.style.display = 'block'; | |
| placeholderResult.style.display = 'none'; | |
| resultContainer.style.display = 'none'; | |
| generateBtn.disabled = true; | |
| // Simulate processing time (in a real app, this would call an API) | |
| setTimeout(() => { | |
| loading.style.display = 'none'; | |
| resultContainer.style.display = 'block'; | |
| // In a real implementation, this would be the result from Qwen Image Edit 2509 | |
| // For demo purposes, we'll use the same image with a filter applied | |
| applyImageFilter(); | |
| // Show notification | |
| notification.style.display = 'block'; | |
| setTimeout(() => { | |
| notification.style.display = 'none'; | |
| }, 3000); | |
| }, 3000); | |
| } | |
| function applyImageFilter() { | |
| // Create a canvas to apply filter effects | |
| const canvas = document.createElement('canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const img = new Image(); | |
| img.onload = function() { | |
| canvas.width = img.width; | |
| canvas.height = img.height; | |
| // Draw original image | |
| ctx.drawImage(img, 0, 0); | |
| // Apply a simple filter for demo (in real app, this would be Qwen processing) | |
| const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
| const data = imageData.data; | |
| // Enhance contrast and saturation slightly | |
| for (let i = 0; i < data.length; i += 4) { | |
| // Increase contrast | |
| data[i] = data[i] < 128 ? data[i] * 0.9 : 255 - (255 - data[i]) * 0.9; // Red | |
| data[i + 1] = data[i + 1] < 128 ? data[i + 1] * 0.9 : 255 - (255 - data[i + 1]) * 0.9; // Green | |
| data[i + 2] = data[i + 2] < 128 ? data[i + 2] * 0.9 : 255 - (255 - data[i + 2]) * 0.9; // Blue | |
| } | |
| ctx.putImageData(imageData, 0, 0); | |
| // Set the result image | |
| resultImage.src = canvas.toDataURL(); | |
| }; | |
| img.src = previewImage.src; | |
| } | |
| function resetForm() { | |
| fileInput.value = ''; | |
| previewImage.src = ''; | |
| previewContainer.style.display = 'none'; | |
| resultContainer.style.display = 'none'; | |
| placeholderResult.style.display = 'block'; | |
| generateBtn.disabled = true; | |
| blurSlider.value = 7; | |
| blurValue.textContent = 7; | |
| enhanceSlider.value = 8; | |
| enhanceValue.textContent = 8; | |
| } | |
| function downloadPortrait() { | |
| if (!resultImage.src) return; | |
| const link = document.createElement('a'); | |
| link.download = 'professional-portrait.png'; | |
| link.href = resultImage.src; | |
| link.click(); | |
| } | |
| // Initialize | |
| resetForm(); | |
| </script> | |
| </body> | |
| </html> |