Spaces:
Running
Running
| {% extends "base.html" %} | |
| {% block title %}Dashboard | AI Avatar Creator{% endblock %} | |
| {% block head_extra %} | |
| <style> | |
| .hero-title { | |
| font-size: 2.8rem; | |
| font-weight: 700; | |
| letter-spacing: -1px; | |
| margin-bottom: 40px; | |
| line-height: 1.2; | |
| color: var(--text-main); | |
| } | |
| .hero-title span { color: var(--text-muted); font-weight: 500; } | |
| .cards-row { | |
| display: flex; | |
| gap: 24px; | |
| margin-bottom: 40px; | |
| flex-wrap: wrap; | |
| } | |
| .ui-card { | |
| flex: 1; | |
| min-width: 280px; | |
| background: var(--card-bg); | |
| border-radius: 24px; | |
| padding: 32px; | |
| box-shadow: var(--shadow-card); | |
| border: 1px solid var(--card-border); | |
| transition: transform 0.2s ease, box-shadow 0.2s ease; | |
| position: relative; | |
| } | |
| .ui-card:hover { | |
| transform: translateY(-4px); | |
| box-shadow: 0 12px 30px rgba(0,0,0,0.05); | |
| } | |
| .card-icon { | |
| width: 48px; height: 48px; border-radius: 14px; | |
| display: flex; align-items: center; justify-content: center; | |
| font-size: 24px; margin-bottom: 24px; | |
| } | |
| .card-icon.yellow { background: #fef3c7; color: #d97706; } | |
| [data-theme="dark"] .card-icon.yellow { background: rgba(217, 119, 6, 0.2); } | |
| .card-icon.red { background: #fee2e2; color: #dc2626; } | |
| [data-theme="dark"] .card-icon.red { background: rgba(220, 38, 38, 0.2); } | |
| .card-icon.blue { background: #e0f2fe; color: #0284c7; } | |
| [data-theme="dark"] .card-icon.blue { background: rgba(2, 132, 199, 0.2); } | |
| .ui-card h3 { font-size: 18px; margin: 0 0 10px 0; font-weight: 600; } | |
| .ui-card p { font-size: 14px; color: var(--text-secondary); margin: 0 0 24px 0; line-height: 1.5; } | |
| /* Custom File Input */ | |
| .custom-file-upload { | |
| display: flex; align-items: center; justify-content: center; gap: 8px; | |
| width: 100%; padding: 14px; background: var(--bg-body); | |
| border: 1px dashed var(--text-muted); border-radius: 12px; | |
| cursor: pointer; font-weight: 500; font-size: 14px; | |
| color: var(--text-main); transition: 0.2s; box-sizing: border-box; | |
| } | |
| .custom-file-upload:hover { border-color: var(--accent-blue); background: rgba(59, 130, 246, 0.05); } | |
| .custom-file-upload input { display: none; } | |
| .filename-display { | |
| margin-top: 10px; font-size: 12px; color: var(--text-secondary); | |
| word-break: break-all; text-align: center; font-weight: 500; | |
| } | |
| /* Custom Select */ | |
| .custom-select { | |
| width: 100%; padding: 14px; border-radius: 12px; border: 1px solid var(--card-border); | |
| background: var(--bg-body); color: var(--text-main); font-size: 14px; | |
| font-family: inherit; font-weight: 500; cursor: pointer; outline: none; | |
| appearance: none; -webkit-appearance: none; | |
| background-image: url('data:image/svg+xml;utf8,<svg fill="%236b7280" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 10l5 5 5-5z"/></svg>'); | |
| background-repeat: no-repeat; background-position: right 12px top 50%; background-size: 16px; | |
| } | |
| .custom-select:focus { border-color: var(--accent-blue); box-shadow: 0 0 0 3px rgba(59,130,246,0.1); } | |
| /* Bottom Action Bar */ | |
| .action-bar { | |
| background: var(--card-bg); border-radius: 20px; padding: 24px; | |
| border: 1px solid var(--card-border); box-shadow: var(--shadow-card); | |
| margin-bottom: 20px; | |
| } | |
| .action-bar-top { | |
| display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; | |
| font-size: 14px; color: var(--text-secondary); | |
| } | |
| .advanced-toggle { | |
| display: flex; align-items: center; gap: 8px; cursor: pointer; | |
| color: var(--text-muted); font-weight: 500; | |
| } | |
| .action-bar-main { | |
| display: flex; flex-wrap: wrap; gap: 12px; align-items: center; | |
| background: var(--bg-body); padding: 12px; border-radius: 16px; | |
| } | |
| /* Input pills inside action bar */ | |
| .pill-input { | |
| background: var(--card-bg); border: 1px solid var(--card-border); | |
| padding: 10px 16px; border-radius: 30px; font-size: 13px; font-weight: 500; | |
| display: inline-flex; align-items: center; gap: 8px; color: var(--text-main); | |
| } | |
| .pill-input input[type="number"] { | |
| border: none; background: transparent; width: 40px; color: var(--text-main); | |
| font-weight: 600; outline: none; text-align: center; | |
| } | |
| .pill-checkbox { | |
| display: flex; align-items: center; gap: 6px; cursor: pointer; | |
| } | |
| .pill-checkbox input { accent-color: var(--btn-dark); width: 16px; height: 16px; cursor: pointer;} | |
| .generate-btn { | |
| background: var(--btn-dark); color: var(--bg-window); | |
| padding: 12px 24px; border-radius: 30px; border: none; font-size: 14px; | |
| font-weight: 600; cursor: pointer; transition: 0.2s; display: inline-flex; | |
| align-items: center; gap: 8px; margin-left: auto; | |
| } | |
| .generate-btn:hover { background: var(--btn-dark-hover); transform: translateY(-1px); } | |
| [data-theme="dark"] .generate-btn { color: #0f172a; } | |
| /* Fun little floating bot from the reference image */ | |
| .floating-bot { | |
| position: absolute; top: -30px; right: 20px; font-size: 45px; | |
| filter: drop-shadow(0 4px 10px rgba(0,0,0,0.1)); | |
| animation: float 3s ease-in-out infinite; | |
| } | |
| @keyframes float { | |
| 0%, 100% { transform: translateY(0); } | |
| 50% { transform: translateY(-8px); } | |
| } | |
| /* Loading Overlay */ | |
| .loading-overlay { | |
| position: fixed; top: 0; left: 0; width: 100%; height: 100%; | |
| background: rgba(255,255,255,0.7); backdrop-filter: blur(10px); | |
| display: none; flex-direction: column; justify-content: center; align-items: center; | |
| z-index: 9999; color: #111827; font-weight: 500; | |
| } | |
| [data-theme="dark"] .loading-overlay { background: rgba(15,23,42,0.8); color: white; } | |
| .loader { | |
| width: 48px; height: 48px; border: 4px solid var(--card-border); | |
| border-bottom-color: var(--btn-dark); border-radius: 50%; | |
| animation: spin 1s linear infinite; margin-bottom: 20px; | |
| } | |
| @keyframes spin { 100% { transform: rotate(360deg); } } | |
| </style> | |
| {% endblock %} | |
| {% block content %} | |
| <h1 class="hero-title"> | |
| Hi Creator, <span>Ready to</span><br>Achieve Great Things? | |
| </h1> | |
| <form action="{{ url_for('infer') }}" method="post" enctype="multipart/form-data" id="inferenceForm"> | |
| <div class="cards-row"> | |
| <!-- Card 1: Face --> | |
| <div class="ui-card"> | |
| <div class="card-icon yellow"><i class="fas fa-layer-group"></i></div> | |
| <h3>Source Material</h3> | |
| <p>Upload the base image or video of the face you want to animate.</p> | |
| <label class="custom-file-upload"> | |
| <input type="file" id="face_file" name="face_file" accept="video/*,image/*" required> | |
| <i class="fas fa-video"></i> Select Face File | |
| </label> | |
| <div id="face_filename" class="filename-display"></div> | |
| </div> | |
| <!-- Card 2: Audio --> | |
| <div class="ui-card"> | |
| <div class="floating-bot">🤖</div> | |
| <div class="card-icon red"><i class="fab fa-slack"></i></div> | |
| <h3>Voice Track</h3> | |
| <p>Provide the audio track to generate perfect lip-syncing synchronization.</p> | |
| <label class="custom-file-upload"> | |
| <input type="file" id="audio_file" name="audio_file" accept="audio/*,video/*" required> | |
| <i class="fas fa-music"></i> Select Audio File | |
| </label> | |
| <div id="audio_filename" class="filename-display"></div> | |
| </div> | |
| <!-- Card 3: Model --> | |
| <div class="ui-card"> | |
| <div class="card-icon blue"><i class="fas fa-calendar-alt"></i></div> | |
| <h3>AI Model Settings</h3> | |
| <p>Select your Wav2Lip checkpoint to process the avatar generation.</p> | |
| <select id="model_select" name="model_select" class="custom-select" required> | |
| <option value="">-- Choose a model --</option> | |
| {% for model in models %} | |
| <option value="{{ model }}">{{ model }}</option> | |
| {% endfor %} | |
| </select> | |
| </div> | |
| </div> | |
| <!-- Action Bar (Mimicking Prompt Input Area) --> | |
| <div class="action-bar"> | |
| <div class="action-bar-top"> | |
| <div class="advanced-toggle"><i class="fas fa-sparkles"></i> Unlock more with Advanced Options</div> | |
| <div><i class="fas fa-cog"></i> Powered by Wav2Lip</div> | |
| </div> | |
| <div class="action-bar-main"> | |
| <!-- Inline settings styled as sleek pills --> | |
| <label class="pill-input pill-checkbox"> | |
| <input type="checkbox" id="static_input" name="static_input"> | |
| Static Image | |
| </label> | |
| <div class="pill-input"> | |
| <i class="fas fa-tachometer-alt text-muted"></i> FPS | |
| <input type="number" id="fps" name="fps" value="25" min="1" max="60"> | |
| </div> | |
| <div class="pill-input"> | |
| <i class="fas fa-compress text-muted"></i> Resize | |
| <input type="number" id="resize_factor" name="resize_factor" value="1" min="1" max="4"> | |
| </div> | |
| <label class="pill-input pill-checkbox"> | |
| <input type="checkbox" id="rotate" name="rotate"> Rotate 90° | |
| </label> | |
| <label class="pill-input pill-checkbox"> | |
| <input type="checkbox" id="nosmooth" name="nosmooth"> No Smooth | |
| </label> | |
| <!-- Submit Button --> | |
| <button type="submit" class="generate-btn"> | |
| <i class="fas fa-paper-plane"></i> Generate Output | |
| </button> | |
| </div> | |
| </div> | |
| </form> | |
| <div class="loading-overlay" id="loadingOverlay"> | |
| <div class="loader"></div> | |
| <h2>Processing your avatar...</h2> | |
| <p style="color: var(--text-secondary); margin-top: 10px;">This may take a few minutes depending on file size.</p> | |
| </div> | |
| {% endblock %} | |
| {% block scripts_extra %} | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // File upload name display | |
| const faceInput = document.getElementById('face_file'); | |
| const faceDisplay = document.getElementById('face_filename'); | |
| faceInput.addEventListener('change', (e) => { | |
| if(e.target.files[0]) faceDisplay.textContent = e.target.files[0].name; | |
| else faceDisplay.textContent = ''; | |
| }); | |
| const audioInput = document.getElementById('audio_file'); | |
| const audioDisplay = document.getElementById('audio_filename'); | |
| audioInput.addEventListener('change', (e) => { | |
| if(e.target.files[0]) audioDisplay.textContent = e.target.files[0].name; | |
| else audioDisplay.textContent = ''; | |
| }); | |
| // Loading state | |
| const form = document.getElementById('inferenceForm'); | |
| const overlay = document.getElementById('loadingOverlay'); | |
| const btn = document.querySelector('.generate-btn'); | |
| form.addEventListener('submit', function() { | |
| overlay.style.display = 'flex'; | |
| btn.disabled = true; | |
| btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Initializing...'; | |
| }); | |
| window.addEventListener('pageshow', function() { | |
| overlay.style.display = 'none'; | |
| btn.disabled = false; | |
| btn.innerHTML = '<i class="fas fa-paper-plane"></i> Generate Output'; | |
| }); | |
| }); | |
| </script> | |
| {% endblock %} |