Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>M3DDM Video Outpainting</title> | |
| <script src="https://cdn.jsdelivr.net/npm/react@18.0.0/umd/react.development.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/react-dom@18.0.0/umd/react-dom.development.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@babel/standalone/babel.js"></script> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| } | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| } | |
| .glass-effect { | |
| background: rgba(255, 255, 255, 0.1); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| .video-container { | |
| background: linear-gradient(145deg, #1a1a2e, #16213e); | |
| border-radius: 12px; | |
| overflow: hidden; | |
| } | |
| .upload-area { | |
| border: 2px dashed #667eea; | |
| transition: all 0.3s ease; | |
| } | |
| .upload-area:hover { | |
| border-color: #764ba2; | |
| background: rgba(102, 126, 234, 0.1); | |
| } | |
| .slider-track { | |
| background: linear-gradient(90deg, #667eea, #764ba2); | |
| } | |
| .loading-spinner { | |
| border: 3px solid rgba(255, 255, 255, 0.3); | |
| border-top: 3px solid #fff; | |
| border-radius: 50%; | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .tab-active { | |
| background: linear-gradient(90deg, #667eea, #764ba2); | |
| color: white; | |
| } | |
| .tab-inactive { | |
| background: rgba(255, 255, 255, 0.1); | |
| color: rgba(255, 255, 255, 0.7); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="root"></div> | |
| <script type="text/babel"> | |
| const { useState, useEffect, useRef } = React; | |
| const App = () => { | |
| const [activeTab, setActiveTab] = useState('upload'); | |
| const [videoFile, setVideoFile] = useState(null); | |
| const [isProcessing, setIsProcessing] = useState(false); | |
| const [processedVideo, setProcessedVideo] = useState(null); | |
| const [outpaintAmount, setOutpaintAmount] = useState(30); | |
| const [quality, setQuality] = useState(75); | |
| const [style, setStyle] = useState('realistic'); | |
| const [progress, setProgress] = useState(0); | |
| const [showPreview, setShowPreview] = useState(false); | |
| const handleFileUpload = (e) => { | |
| const file = e.target.files[0]; | |
| if (file && file.type.startsWith('video/')) { | |
| setVideoFile(file); | |
| setShowPreview(false); | |
| setProcessedVideo(null); | |
| } | |
| }; | |
| const handleProcess = () => { | |
| if (!videoFile) return; | |
| setIsProcessing(true); | |
| setProgress(0); | |
| // Simulate processing | |
| const interval = setInterval(() => { | |
| setProgress(prev => { | |
| if (prev >= 100) { | |
| clearInterval(interval); | |
| setIsProcessing(false); | |
| // Simulate processed video | |
| setTimeout(() => { | |
| setProcessedVideo(URL.createObjectURL(videoFile)); | |
| setShowPreview(true); | |
| }, 500); | |
| return 100; | |
| } | |
| return prev + 10; | |
| }); | |
| }, 200); | |
| }; | |
| const handleDownload = () => { | |
| // In a real app, this would trigger download of processed video | |
| alert('Download functionality would be implemented here'); | |
| }; | |
| return ( | |
| <div className="min-h-screen gradient-bg"> | |
| {/* Header */} | |
| <header className="glass-effect p-4"> | |
| <div className="container mx-auto flex justify-between items-center"> | |
| <h1 className="text-2xl font-bold text-white">M3DDM Video Outpainting</h1> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" className="text-white hover:underline"> | |
| Built with anycoder | |
| </a> | |
| </div> | |
| </header> | |
| {/* Main Content */} | |
| <main className="container mx-auto p-4"> | |
| {/* Tabs */} | |
| <div className="flex space-x-2 mb-6"> | |
| <button | |
| onClick={() => setActiveTab('upload')} | |
| className={`px-6 py-2 rounded-lg font-medium transition-all ${activeTab === 'upload' ? 'tab-active' : 'tab-inactive'}`} | |
| > | |
| <i className="fas fa-upload mr-2"></i> | |
| Upload Video | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('settings')} | |
| className={`px-6 py-2 rounded-lg font-medium transition-all ${activeTab === 'settings' ? 'tab-active' : 'tab-inactive'}`} | |
| > | |
| <i className="fas fa-cog mr-2"></i> | |
| Settings | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('about')} | |
| className={`px-6 py-2 rounded-lg font-medium transition-all ${activeTab === 'about' ? 'tab-active' : 'tab-inactive'}`} | |
| > | |
| <i className="fas fa-info-circle mr-2"></i> | |
| About | |
| </button> | |
| </div> | |
| {/* Upload Section */} | |
| {activeTab === 'upload' && ( | |
| <div className="grid lg:grid-cols-2 gap-6"> | |
| {/* Upload Area */} | |
| <div className="glass-effect rounded-xl p-6"> | |
| <h2 className="text-xl font-semibold text-white mb-4">Upload Video</h2> | |
| <div className="upload-area rounded-lg p-8 text-center cursor-pointer" onClick={() => document.getElementById('videoInput').click()}> | |
| <input | |
| type="file" | |
| id="videoInput" | |
| className="hidden" | |
| accept="video/*" | |
| onChange={handleFileUpload} | |
| /> | |
| <i className="fas fa-cloud-upload-alt text-4xl text-white mb-4"></i> | |
| <p className="text-white mb-2">Click to upload or drag and drop</p> | |
| <p className="text-gray-300 text-sm">MP4, AVI, MOV up to 100MB</p> | |
| {videoFile && ( | |
| <div className="mt-4 p-3 bg-white bg-opacity-10 rounded-lg"> | |
| <p className="text-white text-sm">{videoFile.name}</p> | |
| <p className="text-gray-300 text-xs">{(videoFile.size / 1024 / 1024).toFixed(2)} MB</p> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| {/* Controls */} | |
| <div className="glass-effect rounded-xl p-6"> | |
| <h2 className="text-xl font-semibold text-white mb-4">Processing Controls</h2> | |
| <div className="space-y-4"> | |
| <div> | |
| <label className="text-white text-sm mb-2 block">Outpaint Amount: {outpaintAmount}%</label> | |
| <input | |
| type="range" | |
| min="10" | |
| max="100" | |
| value={outpaintAmount} | |
| onChange={(e) => setOutpaintAmount(e.target.value)} | |
| className="w-full h-2 rounded-lg slider-track appearance-none cursor-pointer" | |
| /> | |
| </div> | |
| <div> | |
| <label className="text-white text-sm mb-2 block">Quality: {quality}%</label> | |
| <input | |
| type="range" | |
| min="50" | |
| max="100" | |
| value={quality} | |
| onChange={(e) => setQuality(e.target.value)} | |
| className="w-full h-2 rounded-lg slider-track appearance-none cursor-pointer" | |
| /> | |
| </div> | |
| <div> | |
| <label className="text-white text-sm mb-2 block">Style</label> | |
| <select | |
| value={style} | |
| onChange={(e) => setStyle(e.target.value)} | |
| className="w-full p-2 rounded-lg bg-white bg-opacity-10 text-white border border-white border-opacity-20" | |
| > | |
| <option value="realistic">Realistic</option> | |
| <option value="artistic">Artistic</option> | |
| <option value="cartoon">Cartoon</option> | |
| </select> | |
| </div> | |
| <button | |
| onClick={handleProcess} | |
| disabled={!videoFile || isProcessing} | |
| className="w-full py-3 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-lg font-medium hover:from-purple-600 hover:to-pink-600 transition-all disabled:opacity-50 disabled:cursor-not-allowed" | |
| > | |
| {isProcessing ? ( | |
| <div className="flex items-center justify-center"> | |
| <div className="loading-spinner mr-3"></div> | |
| Processing... | |
| </div> | |
| ) : 'Process Video'} | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Settings Section */} | |
| {activeTab === 'settings' && ( | |
| <div className="glass-effect rounded-xl p-6"> | |
| <h2 className="text-xl font-semibold text-white mb-4">Advanced Settings</h2> | |
| <div className="grid md:grid-cols-2 gap-6"> | |
| <div> | |
| <h3 className="text-white font-medium mb-3">Performance</h3> | |
| <div className="space-y-3"> | |
| <div className="flex items-center justify-between"> | |
| <span className="text-gray-300">GPU Acceleration</span> | |
| <label className="relative inline-flex items-center cursor-pointer"> | |
| <input type="checkbox" className="sr-only peer" defaultChecked /> | |
| <div className="w-11 h-6 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div> | |
| </label> | |
| </div> | |
| <div className="flex items-center justify-between"> | |
| <span className="text-gray-300">High Resolution</span> | |
| <label className="relative inline-flex items-center cursor-pointer"> | |
| <input type="checkbox" className="sr-only peer" /> | |
| <div className="w-11 h-6 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div> | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 className="text-white font-medium mb-3">Output</h3> | |
| <div className="space-y-3"> | |
| <div> | |
| <label className="text-gray-300 text-sm mb-1 block">Output Format</label> | |
| <select className="w-full p-2 rounded-lg bg-white bg-opacity-10 text-white border border-white border-opacity-20"> | |
| <option>MP4</option> | |
| <option>WebM</option> | |
| <option>AVI</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label className="text-gray-300 text-sm mb-1 block">Frame Rate</label> | |
| <select className="w-full p-2 rounded-lg bg-white bg-opacity-10 text-white border border-white border-opacity-20"> | |
| <option>24 FPS</option> | |
| <option>30 FPS</option> | |
| <option>60 FPS</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* About Section */} | |
| {activeTab === 'about' && ( | |
| <div className="glass-effect rounded-xl p-6"> | |
| <h2 className="text-xl font-semibold text-white mb-4">About M3DDM Video Outpainting</h2> | |
| <div className="text-gray-300 space-y-4"> | |
| <p>M3DDM Video Outpainting is an advanced AI-powered tool that extends video content beyond its original boundaries. Using state-of-the-art machine learning models, it intelligently generates realistic video extensions while maintaining visual consistency.</p> | |
| <div className="grid md:grid-cols-2 gap-4 mt-6"> | |
| <div className="bg-white bg-opacity-10 p-4 rounded-lg"> | |
| <h3 className="text-white font-medium mb-2">Key Features</h3> | |
| <ul className="space-y-1 text-sm"> | |
| <li>• AI-powered video extension</li> | |
| <li>• Multiple style options</li> | |
| <li>• Adjustable outpaint amount</li> | |
| <li>• High-quality output</li> | |
| </ul> | |
| </div> | |
| <div className="bg-white bg-opacity-10 p-4 rounded-lg"> | |
| <h3 className="text-white font-medium mb-2">Technical Details</h3> | |
| <ul className="space-y-1 text-sm"> | |
| <li>• Based on diffusion models</li> | |
| <li>• GPU accelerated processing</li> | |
| <li>• Supports various formats</li> | |
| <li>• Real-time preview</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Video Preview Section */} | |
| {showPreview && ( | |
| <div className="mt-6"> | |
| <div className="glass-effect rounded-xl p-6"> | |
| <div className="flex justify-between items-center mb-4"> | |
| <h2 className="text-xl font-semibold text-white">Preview</h2> | |
| <button | |
| onClick={handleDownload} | |
| className="px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors" | |
| > | |
| <i className="fas fa-download mr-2"></i> | |
| Download | |
| </button> | |
| </div> | |
| <div className="grid lg:grid-cols-2 gap-6"> | |
| <div> | |
| <h3 className="text-white font-medium mb-2">Original Video</h3> | |
| <div className="video-container aspect-video"> | |
| <video controls className="w-full h-full object-cover"> | |
| <source src={URL.createObjectURL(videoFile)} type={videoFile.type} /> | |
| </video> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 className="text-white font-medium mb-2">Processed Video</h3> | |
| <div className="video-container aspect-video"> | |
| <video controls className="w-full h-full object-cover"> | |
| <source src={processedVideo} type={videoFile.type} /> | |
| </video> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Progress Bar */} | |
| {isProcessing && ( | |
| <div className="mt-6 glass-effect rounded-xl p-6"> | |
| <div className="flex items-center justify-between mb-2"> | |
| <span className="text-white">Processing...</span> | |
| <span className="text-white">{progress}%</span> | |
| </div> | |
| <div className="w-full bg-gray-700 rounded-full h-2"> | |
| <div | |
| className="bg-gradient-to-r from-purple-500 to-pink-500 h-2 rounded-full transition-all duration-300" | |
| style={{ width: `${progress}%` }} | |
| ></div> | |
| </div> | |
| </div> | |
| )} | |
| </main> | |
| {/* Footer */} | |
| <footer className="mt-12 py-6 text-center text-gray-300 text-sm"> | |
| <p>M3DDM Video Outpainting © 2024 | Powered by Advanced AI Technology</p> | |
| </footer> | |
| </div> | |
| ); | |
| }; | |
| ReactDOM.render(<App />, document.getElementById('root')); | |
| </script> | |
| </body> | |
| </html> |