Spaces:
Running
Running
| <html> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width" /> | |
| <meta name="description" content="Create unique AI ASMR videos & audio effortlessly. Explore now!" /> | |
| <title>AI ASMR Video Generator</title> | |
| <link rel="stylesheet" href="style.css" /> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header-info"> | |
| <p>Learn more about AI ASMR generation. Try on <a href="https://aiasmr.one" target="_blank">aiasmr.one</a.</p> | |
| </div> | |
| <div class="main-interface"> | |
| <div class="input-panel"> | |
| <div class="upload-section"> | |
| <div class="upload-area" id="uploadArea"> | |
| <div class="upload-icon"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> | |
| <polyline points="17,8 12,3 7,8"></polyline> | |
| <line x1="12" y1="3" x2="12" y2="15"></line> | |
| </svg> | |
| </div> | |
| <div class="upload-text"> | |
| <p>Drop Image Here</p> | |
| <p class="upload-or">- or -</p> | |
| <p>Click to Upload</p> | |
| </div> | |
| <input type="file" id="fileInput" accept="image/*" hidden> | |
| </div> | |
| </div> | |
| <div class="prompt-section"> | |
| <textarea id="promptInput" placeholder="describe the ASMR video you want to generate..." rows="3"></textarea> | |
| </div> | |
| <div class="action-buttons"> | |
| <button class="btn-icon" title="Upload"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> | |
| <polyline points="17,8 12,3 7,8"></polyline> | |
| <line x1="12" y1="3" x2="12" y2="15"></line> | |
| </svg> | |
| </button> | |
| <button class="btn-icon" title="Settings"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <circle cx="12" cy="12" r="3"></circle> | |
| <path d="m12 1 3 6 6 3-6 3-3 6-3-6-6-3 6-3 3-6z"></path> | |
| </svg> | |
| </button> | |
| <button class="btn-icon" title="Clear"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M3 6h18l-2 13H5L3 6z"></path> | |
| <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> | |
| </svg> | |
| </button> | |
| </div> | |
| <button class="generate-button" id="generateBtn"> | |
| Generate! | |
| </button> | |
| <div class="advanced-settings"> | |
| <div class="settings-header" id="settingsToggle"> | |
| <span>Advanced Settings</span> | |
| <svg class="chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <polyline points="6,9 12,15 18,9"></polyline> | |
| </svg> | |
| </div> | |
| <div class="settings-content" id="settingsContent" style="display: none;"> | |
| <div class="setting-item"> | |
| <label>Duration (seconds)</label> | |
| <input type="range" min="5" max="60" value="30" class="slider"> | |
| <span class="value">30</span> | |
| </div> | |
| <div class="setting-item"> | |
| <label>Audio Quality</label> | |
| <select class="select-input"> | |
| <option>Standard</option> | |
| <option>High</option> | |
| <option>Ultra</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="output-panel"> | |
| <div class="video-display" id="videoDisplay"> | |
| <div class="display-placeholder"> | |
| <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1"> | |
| <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect> | |
| <line x1="8" y1="21" x2="16" y2="21"></line> | |
| <line x1="12" y1="17" x2="12" y2="21"></line> | |
| </svg> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="examples-section"> | |
| <div class="examples-header"> | |
| <span>Examples</span> | |
| </div> | |
| <div class="examples-grid" id="examplesGrid"> | |
| <!-- Examples will be generated by JavaScript --> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Examples data array | |
| const examples = [ | |
| { | |
| prompt: "A hyper-realistic cinematic slow-motion close-up video of a whole, full-shaped strawberry made of gold glass, perfectly centered on a wooden cutting board. A human hand holds a sharp stainless steel knife and slices through the glass strawberry. Transparent shards scatter lightly from the cuts. ASMR slicing sounds only. Ultra-sharp macro lens, shallow depth of field, cinematic lighting. Only the hand, knife, and fruit are visible.", | |
| title: "Glass Strawberry Cutting ASMR", | |
| video: "https://files.wan21ai.com/home/aiasmr/blog/how-to-make-ai-asmr-videos-with-prompts/ai-asmr3.mp4" | |
| }, | |
| { | |
| prompt: "A hyper-realistic cinematic close-up of a whole, full-shaped [raspberry] made of blue glass. The glass fruit is perfectly centered on a wooden cutting board, glowing subtly under studio lighting. A human hand is clearly visible, holding a sharp stainless steel knife just above the fruit, ready to slice. In slow motion, the knife makes the first clean slice through the glass fruit -- the front section breaks off cleanly with delicate glass-crack sounds. Then, the knife immediately makes a second slice, cutting another piece smoothly. Transparent shards scatter lightly from both cuts. ASMR slicing sounds only -- no talking, no music. Only the hand, knife, and fruit are visible. Ultra-sharp macro lens, shallow depth of field, cinematic lighting.", | |
| title: "Raspberry Cutting ASMR", | |
| video: "https://files.wan21ai.com/home/aiasmr/blog/how-to-make-ai-asmr-videos-with-prompts/ai-asmr1.mp4" | |
| } | |
| ]; | |
| // Generate examples HTML | |
| function generateExamples() { | |
| const examplesGrid = document.getElementById('examplesGrid'); | |
| examples.forEach((example, index) => { | |
| const exampleItem = document.createElement('div'); | |
| exampleItem.className = 'example-item'; | |
| exampleItem.setAttribute('data-prompt', example.prompt); | |
| exampleItem.setAttribute('data-title', example.title); | |
| exampleItem.innerHTML = ` | |
| <div class="example-content"> | |
| <div class="example-video"> | |
| <video muted preload="none" class="example-video-player" playsinline> | |
| <source src="${example.video}" type="video/mp4"> | |
| Your browser does not support the video tag. | |
| </video> | |
| <div class="play-overlay"> | |
| <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <polygon points="5,3 19,12 5,21"></polygon> | |
| </svg> | |
| </div> | |
| </div> | |
| <div class="example-text"> | |
| <div class="example-prompt">${example.prompt}</div> | |
| </div> | |
| </div> | |
| `; | |
| examplesGrid.appendChild(exampleItem); | |
| }); | |
| } | |
| // Helper function to create video with CORS fallback | |
| function createVideoWithFallback(videoUrl, isPreview = false) { | |
| const video = document.createElement('video'); | |
| if (isPreview) { | |
| video.muted = true; | |
| video.preload = 'none'; | |
| video.classList.add('example-video-player'); | |
| video.setAttribute('playsinline', ''); | |
| } else { | |
| video.controls = true; | |
| video.preload = 'auto'; | |
| video.classList.add('result-video'); | |
| } | |
| const source = document.createElement('source'); | |
| source.src = videoUrl; | |
| source.type = 'video/mp4'; | |
| video.appendChild(source); | |
| // Handle CORS errors gracefully | |
| video.addEventListener('error', () => { | |
| console.log('Video error, trying without CORS restrictions'); | |
| // For preview videos, just hide the error | |
| if (isPreview) { | |
| video.style.opacity = '0.5'; | |
| return; | |
| } | |
| }); | |
| return video; | |
| } | |
| // Initialize examples on page load | |
| document.addEventListener('DOMContentLoaded', () => { | |
| generateExamples(); | |
| attachExampleListeners(); | |
| }); | |
| // File upload handling | |
| const uploadArea = document.getElementById('uploadArea'); | |
| const fileInput = document.getElementById('fileInput'); | |
| uploadArea.addEventListener('click', () => { | |
| fileInput.click(); | |
| }); | |
| uploadArea.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| uploadArea.classList.add('drag-over'); | |
| }); | |
| uploadArea.addEventListener('dragleave', () => { | |
| uploadArea.classList.remove('drag-over'); | |
| }); | |
| uploadArea.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| uploadArea.classList.remove('drag-over'); | |
| const files = e.dataTransfer.files; | |
| if (files.length > 0) { | |
| handleFile(files[0]); | |
| } | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| if (e.target.files.length > 0) { | |
| handleFile(e.target.files[0]); | |
| } | |
| }); | |
| function handleFile(file) { | |
| if (file.type.startsWith('image/')) { | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| uploadArea.style.backgroundImage = `url(${e.target.result})`; | |
| uploadArea.style.backgroundSize = 'cover'; | |
| uploadArea.style.backgroundPosition = 'center'; | |
| uploadArea.classList.add('has-image'); | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| } | |
| // Generate button | |
| document.getElementById('generateBtn').addEventListener('click', () => { | |
| window.open('https://aiasmr.one/dashboard', '_blank'); | |
| }); | |
| // Advanced settings toggle | |
| document.getElementById('settingsToggle').addEventListener('click', () => { | |
| const content = document.getElementById('settingsContent'); | |
| const chevron = document.querySelector('.chevron'); | |
| if (content.style.display === 'none') { | |
| content.style.display = 'block'; | |
| chevron.style.transform = 'rotate(180deg)'; | |
| } else { | |
| content.style.display = 'none'; | |
| chevron.style.transform = 'rotate(0deg)'; | |
| } | |
| }); | |
| // Attach example click listeners | |
| function attachExampleListeners() { | |
| document.querySelectorAll('.example-item').forEach((item, index) => { | |
| item.addEventListener('click', () => { | |
| const prompt = item.getAttribute('data-prompt'); | |
| const title = item.getAttribute('data-title'); | |
| const example = examples[index]; | |
| document.getElementById('promptInput').value = prompt; | |
| // Update video display | |
| const videoDisplay = document.getElementById('videoDisplay'); | |
| // Try different approaches for CORS issues | |
| const createVideoElement = () => { | |
| return ` | |
| <div class="video-preview"> | |
| <video controls preload="auto" class="result-video"> | |
| <source src="${example.video}" type="video/mp4"> | |
| Your browser does not support the video tag. | |
| </video> | |
| <div class="video-info"> | |
| <p>${title}</p> | |
| <small>Example video loaded - Click play to watch</small> | |
| </div> | |
| </div> | |
| `; | |
| }; | |
| videoDisplay.innerHTML = createVideoElement(); | |
| // Force video to load and add comprehensive error handling | |
| const video = videoDisplay.querySelector('video'); | |
| // Remove crossorigin initially, add only if needed | |
| video.removeAttribute('crossorigin'); | |
| video.load(); | |
| video.addEventListener('error', (e) => { | |
| console.error('Video loading error:', e); | |
| console.log('Trying alternative loading method...'); | |
| // Try with crossorigin as fallback | |
| if (!video.hasAttribute('crossorigin')) { | |
| video.setAttribute('crossorigin', 'anonymous'); | |
| video.load(); | |
| return; | |
| } | |
| // If still fails, try use-credentials | |
| if (video.getAttribute('crossorigin') === 'anonymous') { | |
| video.setAttribute('crossorigin', 'use-credentials'); | |
| video.load(); | |
| return; | |
| } | |
| // Final fallback - provide direct link | |
| videoDisplay.innerHTML = ` | |
| <div class="video-fallback"> | |
| <div class="video-link-container"> | |
| <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1"> | |
| <polygon points="5,3 19,12 5,21"></polygon> | |
| </svg> | |
| <p>Video cannot be embedded due to CORS policy</p> | |
| <a href="${example.video}" target="_blank" class="video-link-btn"> | |
| Open Video in New Tab | |
| </a> | |
| </div> | |
| <div class="video-info"> | |
| <p>${title}</p> | |
| <small>Click the link above to watch the video</small> | |
| </div> | |
| </div> | |
| `; | |
| }); | |
| video.addEventListener('loadeddata', () => { | |
| console.log('Video loaded successfully'); | |
| }); | |
| // Add additional event listeners for debugging | |
| video.addEventListener('loadstart', () => { | |
| console.log('Video loading started'); | |
| }); | |
| video.addEventListener('canplay', () => { | |
| console.log('Video can start playing'); | |
| }); | |
| // Remove previous selection | |
| document.querySelectorAll('.example-item').forEach(el => el.classList.remove('selected')); | |
| item.classList.add('selected'); | |
| }); | |
| }); | |
| } | |
| // Slider value update | |
| document.querySelectorAll('.slider').forEach(slider => { | |
| slider.addEventListener('input', (e) => { | |
| const valueSpan = e.target.nextElementSibling; | |
| valueSpan.textContent = e.target.value; | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |