CoolFace
Apppublic

ALSv/self-forcing

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
demo.html616 linesDownload Raw Back to templates
1<!DOCTYPE html>2<html lang="en">3<head>4    <meta charset="UTF-8">5    <meta name="viewport" content="width=device-width, initial-scale=1.0">6    <title>Self Forcing</title>7    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>8    <style>9        body {10            font-family: Arial, sans-serif;11            max-width: 1400px;12            margin: 0 auto;13            padding: 20px;14            background-color: #f5f5f5;15        }16        .container {17            background: white;18            padding: 20px;19            border-radius: 10px;20            box-shadow: 0 2px 10px rgba(0,0,0,0.1);21        }22        .main-layout {23            display: grid;24            grid-template-columns: 1fr 1fr;25            gap: 30px;26            margin-top: 20px;27        }28        .left-column {29            padding-right: 15px;30        }31        .right-column {32            padding-left: 15px;33        }34        @media (max-width: 768px) {35            .main-layout {36                grid-template-columns: 1fr;37                gap: 20px;38            }39            .left-column, .right-column {40                padding: 0;41            }42        }43        .controls {44            margin-bottom: 20px;45        }46        .control-group {47            margin-bottom: 15px;48        }49        label {50            display: block;51            margin-bottom: 5px;52            font-weight: bold;53        }54        input, textarea, button, select {55            padding: 8px;56            border: 1px solid #ddd;57            border-radius: 4px;58        }59        textarea {60            width: 100%;61            height: 90px;62            resize: vertical;63        }64        input[type="range"] {65            width: 200px;66        }67        button {68            background-color: #007bff;69            color: white;70            border: none;71            padding: 10px 20px;72            cursor: pointer;73            margin-right: 10px;74        }75        button:hover {76            background-color: #0056b3;77        }78        button:disabled {79            background-color: #6c757d;80            cursor: not-allowed;81        }82        .stop-btn {83            background-color: #dc3545;84        }85        .stop-btn:hover {86            background-color: #c82333;87        }88        .video-container {89            text-align: center;90            background: #000;91            border-radius: 8px;92            padding: 20px;93            margin: 20px auto;94            display: flex;95            flex-direction: column;96            align-items: center;97            justify-content: center;98        }99        #videoFrame {100            max-width: 100%;101            height: auto;102            border-radius: 4px;103        }104        .progress-container {105            margin: 20px 0;106        }107        .progress-bar {108            width: 100%;109            height: 20px;110            background-color: #e9ecef;111            border-radius: 10px;112            overflow: hidden;113        }114        .progress-fill {115            height: 100%;116            background-color: #007bff;117            transition: width 0.3s ease;118        }119        .status {120            margin: 10px 0;121            padding: 10px;122            border-radius: 4px;123        }124        .status.info {125            background-color: #d1ecf1;126            color: #0c5460;127        }128        .status.error {129            background-color: #f8d7da;130            color: #721c24;131        }132        .status.success {133            background-color: #d4edda;134            color: #155724;135        }136        .frame-info {137            color: #666;138            font-size: 0.9em;139            margin-top: 10px;140        }141        .buffer-info {142            background-color: #e3f2fd;143            padding: 15px;144            border-radius: 4px;145            margin: 15px 0;146            color: #1976d2;147        }148        .playback-controls {149            margin: 15px 0;150            display: flex;151            align-items: center;152            justify-content: center;153            gap: 10px;154        }155        .playback-controls button {156            margin: 0 5px;157            padding: 8px 15px;158        }159        #playbackSpeed {160            width: 80px;161        }162        .torch-compile-toggle {163            background-color: #f8f9fa;164            border: 1px solid #dee2e6;165            border-radius: 6px;166            padding: 10px;167            margin: 0;168            flex: 1;169            min-width: 120px;170        }171        .torch-compile-toggle label {172            display: flex;173            align-items: center;174            font-weight: bold;175            color: #495057;176            margin-bottom: 0;177            font-size: 0.9em;178        }179        .torch-compile-toggle input[type="checkbox"] {180            transform: scale(1.1);181            margin-right: 8px;182        }183    </style>184</head>185<body>186    <div class="container">187        <h1>🚀 Self Forcing</h1>188 189        <div class="main-layout">190            <div class="left-column">191                <div class="controls">192                    <div class="control-group">193                        <label for="prompt">Prompt (long, detailed prompts work better):</label>194                        <textarea id="prompt" placeholder="Describe the video you want to generate..."></textarea>195 196                        <div style="margin-top: 10px;">197                            <label>Quick Prompts:</label>198                            <div style="display: flex; flex-direction: column; gap: 8px; margin-top: 5px;">199                                <button type="button" onclick="setQuickPrompt('quick-demo-1')" style="background-color: #28a745; font-size: 11px; padding: 8px; width: 100%; text-align: left; white-space: pre-wrap; line-height: 1.3; min-height: 60px; border-radius: 4px; color: white; border: none; cursor: pointer;">A stylish woman walks down a Tokyo street filled with warm glowing neon and animated city signage. She wears a black leather jacket, a long red dress, and black boots, and carries a black purse. She wears sunglasses and red lipstick. She walks confidently and casually. The street is damp and reflective, creating a mirror effect of the colorful lights. Many pedestrians walk about.</button>200                                <button type="button" onclick="setQuickPrompt('quick-demo-2')" style="background-color: #17a2b8; font-size: 11px; padding: 8px; width: 100%; text-align: left; white-space: pre-wrap; line-height: 1.3; min-height: 60px; border-radius: 4px; color: white; border: none; cursor: pointer;">A white and orange tabby cat is seen happily darting through a dense garden, as if chasing something. Its eyes are wide and happy as it jogs forward, scanning the branches, flowers, and leaves as it walks. The path is narrow as it makes its way between all the plants. the scene is captured from a ground-level angle, following the cat closely, giving a low and intimate perspective. The image is cinematic with warm tones and a grainy texture. The scattered daylight between the leaves and plants above creates a warm contrast, accentuating the cat’s orange fur. The shot is clear and sharp, with a shallow depth of field.</button>201                            </div>202                        </div>203                    </div>204 205                    <div style="display: flex; gap: 20px;">206                        <div class="control-group">207                            <label for="seed">Seed:</label>208                            <input type="number" id="seed" value="-1" min="0" max="999999">209                        </div>210 211                        <div class="control-group">212                            <label for="fps">Target FPS: <span id="fpsValue">6</span></label>213                            <input type="range" id="fps" min="2" max="16" value="6" step="0.5">214                        </div>215 216                        <!-- <div class="control-group">217                            <label for="blocks">Total Blocks: <span id="blocksValue">7</span></label>218                            <input type="range" id="blocks" min="3" max="10" value="7" step="1">219                        </div> -->220                    </div>221 222                    <div class="control-group">223                        <div style="display: flex; gap: 15px; align-items: flex-start; flex-wrap: wrap;">224                            <div class="torch-compile-toggle">225                                <label>226                                    <input type="checkbox" id="torchCompile">227                                    🔥 torch.compile228                                </label>229                            </div>230                            <div class="torch-compile-toggle">231                                <label>232                                    <input type="checkbox" id="fp8Toggle">233                                    ⚡ FP8 Quantization234                                </label>235                            </div>236                            <div class="torch-compile-toggle">237                                <label>238                                    <input type="checkbox" id="taehvToggle">239                                    ⚡ TAEHV VAE240                                </label>241                            </div>242                        </div>243                        <!-- <div style="font-size: 0.85em; color: #666; margin-top: 5px;">244                            <strong>Note:</strong> torch.compile and FP8 are one-time toggles (cannot be changed once applied)245                        </div> -->246                    </div>247 248                    <div class="control-group">249                        <button id="startBtn" onclick="startGeneration()">🚀 Start Generation</button>250                        <button id="stopBtn" onclick="stopGeneration()" disabled class="stop-btn">⏹️ Stop</button>251                    </div>252                </div>253 254                <div class="progress-container">255                    <div class="progress-bar">256                        <div id="progressFill" class="progress-fill" style="width: 0%"></div>257                    </div>258                    <div id="progressText">Ready to generate</div>259                </div>260            </div>261 262            <div class="right-column">263                <div class="buffer-info">264                    <strong>📦 Frame Buffer:</strong> <span id="bufferCount">0</span> frames ready |265                    <strong>📺 Displayed:</strong> <span id="displayedCount">0</span> frames266                    <!-- <strong>⚡ Receive Rate:</strong> <span id="receiveRate">0</span> fps -->267                </div>268 269                <div class="playback-controls">270                    <button id="playBtn" onclick="togglePlayback()" disabled>▶️ Play</button>271                    <button id="resetBtn" onclick="resetPlayback()" disabled>⏮️ Reset</button>272                    <label for="playbackSpeed">Speed:</label>273                    <select id="playbackSpeed" onchange="updatePlaybackSpeed()">274                        <option value="0.25">0.25x</option>275                        <option value="0.5">0.5x</option>276                        <option value="0.75">0.75x</option>277                        <option value="1" selected>1x</option>278                        <option value="1.25">1.25x</option>279                        <option value="1.5">1.5x</option>280                        <option value="2">2x</option>281                    </select>282                </div>283 284                <div id="statusContainer"></div>285 286                <div class="video-container">287                    <img id="videoFrame" src="" alt="Video frames will appear here" style="display: none;">288                    <div id="placeholderText">Click "Start Generation" to begin</div>289                    <div id="frameInfo" class="frame-info"></div>290                </div>291            </div>292        </div>293    </div>294 295    <script>296        const socket = io();297        let frameBuffer = [];  // Store all received frames298        let currentFrameIndex = 0;299        let isPlaying = false;300        let playbackInterval = null;301        let targetFps = 6;302        let playbackSpeed = 1.0;303        let startTime = null;304        let lastReceiveTime = null;305        let receiveCount = 0;306        let receiveRate = 0;307 308        // State tracking for one-time toggles309        let torchCompileApplied = false;310        let fp8Applied = false;311 312        // Update slider values313        document.getElementById('fps').oninput = function() {314            targetFps = parseFloat(this.value);315            document.getElementById('fpsValue').textContent = this.value;316            updatePlaybackTiming();317        };318 319        // document.getElementById('blocks').oninput = function() {320        //     document.getElementById('blocksValue').textContent = this.value;321        // };322 323        // Handle toggle behavior and fetch current status324        function updateToggleStates() {325            fetch('/api/status')326                .then(response => response.json())327                .then(data => {328                    torchCompileApplied = data.torch_compile_applied;329                    fp8Applied = data.fp8_applied;330 331                    // Update UI based on current state332                    const torchToggle = document.getElementById('torchCompile');333                    const fp8Toggle = document.getElementById('fp8Toggle');334                    const taehvToggle = document.getElementById('taehvToggle');335 336                    // Disable one-time toggles if already applied337                    if (torchCompileApplied) {338                        torchToggle.checked = true;339                        torchToggle.disabled = true;340                        torchToggle.parentElement.style.opacity = '0.6';341                    }342 343                    if (fp8Applied) {344                        fp8Toggle.checked = true;345                        fp8Toggle.disabled = true;346                        fp8Toggle.parentElement.style.opacity = '0.6';347                    }348 349                    // Set TAEHV toggle based on current state350                    taehvToggle.checked = data.current_use_taehv;351                })352                .catch(err => console.log('Status check failed:', err));353        }354 355        // Handle torch.compile toggle356        document.getElementById('torchCompile').onchange = function() {357            if (torchCompileApplied && !this.checked) {358                this.checked = true; // Prevent unchecking359                alert('torch.compile cannot be disabled once applied');360            }361        };362 363        // Handle FP8 toggle364        document.getElementById('fp8Toggle').onchange = function() {365            if (fp8Applied && !this.checked) {366                this.checked = true; // Prevent unchecking367                alert('FP8 quantization cannot be disabled once applied');368            }369        };370 371        // Update toggle states on page load372        updateToggleStates();373 374        // Socket event handlers375        socket.on('connect', function() {376            // showStatus('Connected to frontend-buffered server', 'info');377        });378 379        socket.on('status', function(data) {380            // showStatus(data.message, 'info');381        });382 383        socket.on('progress', function(data) {384            updateProgress(data.progress, data.message);385        });386 387        socket.on('frame_ready', function(data) {388            // Add frame to buffer immediately389            frameBuffer.push(data);390            receiveCount++;391 392            // Calculate receive rate393            const now = Date.now();394            if (lastReceiveTime) {395                const interval = (now - lastReceiveTime) / 1000;396                receiveRate = (1 / interval).toFixed(1);397            }398            lastReceiveTime = now;399 400            updateBufferInfo();401 402            // Auto-start playback when we have some frames403            if (frameBuffer.length === 5 && !isPlaying) {404                // showStatus('Auto-starting playback with buffer of 5 frames', 'info');405                startPlayback();406            }407        });408 409        socket.on('generation_complete', function(data) {410            // showStatus(data.message + ` (Generated in ${data.generation_time})`, 'success');411            enableControls(true);412            const duration = startTime ? ((Date.now() - startTime) / 1000).toFixed(1) : 'unknown';413            updateFrameInfo(`Generation complete! ${data.total_frames} frames in ${duration}s`);414 415            // Update toggle states after generation416            updateToggleStates();417        });418 419        socket.on('error', function(data) {420            // showStatus(`Error: ${data.message}`, 'error');421            enableControls(true);422        });423 424        function startGeneration() {425            const prompt = document.getElementById('prompt').value.trim();426            if (!prompt) {427                alert('Please enter a prompt');428                return;429            }430 431            const seed = parseInt(document.getElementById('seed').value) || 31337;432            // const totalBlocks = parseInt(document.getElementById('blocks').value) || 7;433            const enableTorchCompile = document.getElementById('torchCompile').checked;434            const enableFp8 = document.getElementById('fp8Toggle').checked;435            const useTaehv = document.getElementById('taehvToggle').checked;436 437            // Reset state438            frameBuffer = [];439            currentFrameIndex = 0;440            receiveCount = 0;441            receiveRate = 0;442            stopPlayback();443 444            enableControls(false);445            startTime = Date.now();446 447            socket.emit('start_generation', {448                prompt: prompt,449                seed: seed,450                enable_torch_compile: enableTorchCompile,451                enable_fp8: enableFp8,452                use_taehv: useTaehv453            });454        }455 456        function stopGeneration() {457            socket.emit('stop_generation');458            enableControls(true);459        }460 461        function togglePlayback() {462            if (isPlaying) {463                stopPlayback();464            } else {465                startPlayback();466            }467        }468 469        function startPlayback() {470            if (frameBuffer.length === 0) return;471 472            isPlaying = true;473            document.getElementById('playBtn').textContent = '⏸️ Pause';474            document.getElementById('playBtn').disabled = false;475            document.getElementById('resetBtn').disabled = false;476 477            updatePlaybackTiming();478            // showStatus('Playback started', 'info');479        }480 481        function stopPlayback() {482            isPlaying = false;483            if (playbackInterval) {484                clearInterval(playbackInterval);485                playbackInterval = null;486            }487            document.getElementById('playBtn').textContent = '▶️ Play';488        }489 490        function resetPlayback() {491            stopPlayback();492 493            // Clear the entire frame buffer494            frameBuffer = [];495            currentFrameIndex = 0;496            receiveCount = 0;497            receiveRate = 0;498 499            // Reset video display to initial state500            const img = document.getElementById('videoFrame');501            const placeholder = document.getElementById('placeholderText');502 503            img.src = '';504            img.style.display = 'none';505            placeholder.style.display = 'block';506 507            // Update UI508            updateBufferInfo();509            updateFrameInfo('Reset - buffer cleared');510 511            // Disable playback controls since there's no content512            document.getElementById('playBtn').disabled = true;513            document.getElementById('resetBtn').disabled = true;514        }515 516        function updatePlaybackSpeed() {517            playbackSpeed = parseFloat(document.getElementById('playbackSpeed').value);518            if (isPlaying) {519                updatePlaybackTiming();520            }521        }522 523        function updatePlaybackTiming() {524            if (playbackInterval) {525                clearInterval(playbackInterval);526            }527 528            if (isPlaying) {529                const interval = (1000 / targetFps) / playbackSpeed;530                playbackInterval = setInterval(displayNextFrame, interval);531            }532        }533 534        function displayNextFrame() {535            if (currentFrameIndex >= frameBuffer.length) {536                // Reached end of buffer537                if (document.querySelector('#progressFill').style.width === '100%') {538                    // Generation complete, stop playback539                    stopPlayback();540                    // showStatus('Playback complete', 'success');541                }542                return;543            }544 545            const frameData = frameBuffer[currentFrameIndex];546            displayFrame(frameData);547            currentFrameIndex++;548 549            updateBufferInfo();550        }551 552        function displayFrame(frameData) {553            const img = document.getElementById('videoFrame');554            const placeholder = document.getElementById('placeholderText');555 556            img.src = frameData.data;557            img.style.display = 'block';558            placeholder.style.display = 'none';559 560            const elapsed = startTime ? ((Date.now() - startTime) / 1000).toFixed(1) : '0';561            updateFrameInfo(`Frame ${frameData.frame_index + 1} | Block ${frameData.block_index + 1} | ${elapsed}s elapsed | ${targetFps} FPS @ ${playbackSpeed}x speed`);562        }563 564        function updateBufferInfo() {565            document.getElementById('bufferCount').textContent = frameBuffer.length;566            document.getElementById('displayedCount').textContent = currentFrameIndex;567            // document.getElementById('receiveRate').textContent = receiveRate;568        }569 570        function setQuickPrompt(type) {571            const promptBox = document.getElementById('prompt');572            if (type === 'quick-demo-1') {573                promptBox.value = 'A stylish woman walks down a Tokyo street filled with warm glowing neon and animated city signage. She wears a black leather jacket, a long red dress, and black boots, and carries a black purse. She wears sunglasses and red lipstick. She walks confidently and casually. The street is damp and reflective, creating a mirror effect of the colorful lights. Many pedestrians walk about.';574            } else if (type === 'quick-demo-2') {575                promptBox.value = 'A white and orange tabby cat is seen happily darting through a dense garden, as if chasing something. Its eyes are wide and happy as it jogs forward, scanning the branches, flowers, and leaves as it walks. The path is narrow as it makes its way between all the plants. the scene is captured from a ground-level angle, following the cat closely, giving a low and intimate perspective. The image is cinematic with warm tones and a grainy texture. The scattered daylight between the leaves and plants above creates a warm contrast, accentuating the cat’s orange fur. The shot is clear and sharp, with a shallow depth of field.';576            }577        }578 579        function enableControls(enabled) {580            document.getElementById('startBtn').disabled = !enabled;581            document.getElementById('stopBtn').disabled = enabled;582        }583 584        function updateProgress(progress, message) {585            document.getElementById('progressFill').style.width = progress + '%';586            document.getElementById('progressText').textContent = message;587        }588 589        function updateFrameInfo(text) {590            document.getElementById('frameInfo').textContent = text;591        }592 593        function showStatus(message, type) {594            const container = document.getElementById('statusContainer');595            const statusDiv = document.createElement('div');596            statusDiv.className = `status ${type}`;597            statusDiv.textContent = message;598 599            container.insertBefore(statusDiv, container.firstChild);600 601            // Remove old status messages (keep only last 3)602            while (container.children.length > 3) {603                container.removeChild(container.lastChild);604            }605 606            // Auto-remove after 5 seconds607            setTimeout(() => {608                if (statusDiv.parentNode) {609                    statusDiv.parentNode.removeChild(statusDiv);610                }611            }, 5000);612        }613    </script>614</body>615</html>616