| <!DOCTYPE html> |
| <html lang="vi"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Video Generator API</title> |
| <style> |
| body { |
| font-family: Arial, sans-serif; |
| max-width: 800px; |
| margin: 0 auto; |
| padding: 20px; |
| background-color: #f5f5f5; |
| } |
| .container { |
| background: white; |
| padding: 30px; |
| border-radius: 10px; |
| box-shadow: 0 2px 10px rgba(0,0,0,0.1); |
| } |
| h1 { |
| color: #333; |
| text-align: center; |
| } |
| .section { |
| margin: 30px 0; |
| padding: 20px; |
| border: 1px solid #ddd; |
| border-radius: 5px; |
| } |
| .section h2 { |
| color: #555; |
| margin-top: 0; |
| } |
| input[type="text"] { |
| width: 100%; |
| padding: 10px; |
| border: 1px solid #ddd; |
| border-radius: 5px; |
| margin: 10px 0; |
| } |
| button { |
| background: #007bff; |
| color: white; |
| padding: 10px 20px; |
| border: none; |
| border-radius: 5px; |
| cursor: pointer; |
| margin: 5px; |
| } |
| button:hover { |
| background: #0056b3; |
| } |
| .result { |
| margin: 20px 0; |
| padding: 15px; |
| background: #f8f9fa; |
| border-radius: 5px; |
| border-left: 4px solid #007bff; |
| } |
| .error { |
| border-left-color: #dc3545; |
| background: #f8d7da; |
| } |
| .success { |
| border-left-color: #28a745; |
| background: #d4edda; |
| } |
| .code { |
| background: #f4f4f4; |
| padding: 10px; |
| border-radius: 5px; |
| font-family: monospace; |
| margin: 10px 0; |
| } |
| .status { |
| font-weight: bold; |
| padding: 5px 10px; |
| border-radius: 3px; |
| display: inline-block; |
| margin: 5px 0; |
| } |
| .status.pending { background: #ffc107; color: #212529; } |
| .status.processing { background: #17a2b8; color: white; } |
| .status.completed { background: #28a745; color: white; } |
| .status.failed { background: #dc3545; color: white; } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <h1>🎬 Video Generator API</h1> |
| <p>API để tự động tạo video từ prompt sử dụng Hugging Face Self-Forcing</p> |
|
|
| |
| <div class="section"> |
| <h2>🧪 Test API</h2> |
| <input type="text" id="promptInput" placeholder="Nhập prompt để tạo video (ví dụ: A dog running in a park)" value="A cat playing with a ball"> |
| <button onclick="generateVideo()">Tạo Video</button> |
| <button onclick="checkStatus()">Kiểm tra trạng thái</button> |
| <button onclick="listJobs()">Danh sách Jobs</button> |
| |
| <div id="result"></div> |
| </div> |
|
|
| |
| <div class="section"> |
| <h2>📖 Hướng dẫn sử dụng API</h2> |
| |
| <h3>1. Tạo video từ prompt</h3> |
| <div class="code"> |
| GET /api/video/generate/<prompt> |
| </div> |
| <p><strong>Ví dụ:</strong></p> |
| <div class="code"> |
| GET /api/video/generate/A%20dog%20running%20in%20a%20park |
| </div> |
| <p><strong>Response:</strong></p> |
| <div class="code"> |
| { |
| "success": true, |
| "job_id": "uuid-here", |
| "message": "Video generation started", |
| "status_url": "/api/video/status/uuid-here", |
| "download_url": "/api/video/download/uuid-here" |
| } |
| </div> |
|
|
| <h3>2. Kiểm tra trạng thái</h3> |
| <div class="code"> |
| GET /api/video/status/<job_id> |
| </div> |
| <p><strong>Response:</strong></p> |
| <div class="code"> |
| { |
| "success": true, |
| "job_id": "uuid-here", |
| "status": "completed", |
| "prompt": "A dog running in a park", |
| "video_ready": true, |
| "download_url": "/api/video/download/uuid-here" |
| } |
| </div> |
|
|
| <h3>3. Tải xuống video</h3> |
| <div class="code"> |
| GET /api/video/download/<job_id> |
| </div> |
| <p>Trả về file video để tải xuống.</p> |
|
|
| <h3>4. Danh sách tất cả jobs</h3> |
| <div class="code"> |
| GET /api/video/jobs |
| </div> |
|
|
| <h3>5. Health check</h3> |
| <div class="code"> |
| GET /api/video/health |
| </div> |
| </div> |
|
|
| |
| <div class="section"> |
| <h2>💡 Ví dụ sử dụng</h2> |
| <p>Để tạo video với prompt "tạo ảnh một chú chó", bạn có thể gọi:</p> |
| <div class="code"> |
| https://your-api.com/api/video/generate/tạo%20ảnh%20một%20chú%20chó |
| </div> |
| <p>Sau đó kiểm tra trạng thái và tải xuống video khi hoàn thành.</p> |
| </div> |
| </div> |
|
|
| <script> |
| let currentJobId = null; |
| |
| function showResult(message, type = 'result') { |
| const resultDiv = document.getElementById('result'); |
| resultDiv.innerHTML = `<div class="result ${type}">${message}</div>`; |
| } |
| |
| async function generateVideo() { |
| const prompt = document.getElementById('promptInput').value.trim(); |
| if (!prompt) { |
| showResult('Vui lòng nhập prompt!', 'error'); |
| return; |
| } |
| |
| try { |
| showResult('Đang gửi yêu cầu tạo video...', 'result'); |
| |
| const response = await fetch(`/api/video/generate/${encodeURIComponent(prompt)}`); |
| const data = await response.json(); |
| |
| if (data.success) { |
| currentJobId = data.job_id; |
| showResult(` |
| <strong>✅ Đã bắt đầu tạo video!</strong><br> |
| Job ID: ${data.job_id}<br> |
| Status URL: ${data.status_url}<br> |
| Download URL: ${data.download_url} |
| `, 'success'); |
| |
| |
| setTimeout(checkStatus, 5000); |
| } else { |
| showResult(`❌ Lỗi: ${data.error}`, 'error'); |
| } |
| } catch (error) { |
| showResult(`❌ Lỗi kết nối: ${error.message}`, 'error'); |
| } |
| } |
| |
| async function checkStatus() { |
| if (!currentJobId) { |
| showResult('Chưa có job nào được tạo!', 'error'); |
| return; |
| } |
| |
| try { |
| const response = await fetch(`/api/video/status/${currentJobId}`); |
| const data = await response.json(); |
| |
| if (data.success) { |
| const statusClass = data.status; |
| let message = ` |
| <strong>📊 Trạng thái Job</strong><br> |
| Job ID: ${data.job_id}<br> |
| Prompt: ${data.prompt}<br> |
| Status: <span class="status ${statusClass}">${data.status}</span><br> |
| `; |
| |
| if (data.status === 'completed' && data.video_ready) { |
| message += `<br><a href="${data.download_url}" target="_blank"> |
| <button>📥 Tải xuống video</button> |
| </a>`; |
| } else if (data.status === 'failed') { |
| message += `<br>❌ Lỗi: ${data.error || 'Unknown error'}`; |
| } else if (data.status === 'processing') { |
| message += `<br>⏳ Đang xử lý... Sẽ kiểm tra lại sau 10 giây.`; |
| setTimeout(checkStatus, 10000); |
| } |
| |
| showResult(message, data.status === 'completed' ? 'success' : 'result'); |
| } else { |
| showResult(`❌ Lỗi: ${data.error}`, 'error'); |
| } |
| } catch (error) { |
| showResult(`❌ Lỗi kết nối: ${error.message}`, 'error'); |
| } |
| } |
| |
| async function listJobs() { |
| try { |
| const response = await fetch('/api/video/jobs'); |
| const data = await response.json(); |
| |
| if (data.success) { |
| let message = `<strong>📋 Danh sách Jobs (${data.total})</strong><br><br>`; |
| |
| if (data.jobs.length === 0) { |
| message += 'Chưa có job nào.'; |
| } else { |
| data.jobs.forEach(job => { |
| message += ` |
| <div style="border: 1px solid #ddd; padding: 10px; margin: 5px 0; border-radius: 5px;"> |
| <strong>Job:</strong> ${job.job_id}<br> |
| <strong>Prompt:</strong> ${job.prompt}<br> |
| <strong>Status:</strong> <span class="status ${job.status}">${job.status}</span><br> |
| ${job.download_url ? `<a href="${job.download_url}" target="_blank"><button>📥 Tải xuống</button></a>` : ''} |
| </div> |
| `; |
| }); |
| } |
| |
| showResult(message, 'result'); |
| } else { |
| showResult(`❌ Lỗi: ${data.error}`, 'error'); |
| } |
| } catch (error) { |
| showResult(`❌ Lỗi kết nối: ${error.message}`, 'error'); |
| } |
| } |
| |
| |
| window.onload = async function() { |
| try { |
| const response = await fetch('/api/video/health'); |
| const data = await response.json(); |
| if (data.success) { |
| console.log('✅ API đang hoạt động:', data); |
| } |
| } catch (error) { |
| console.error('❌ API không hoạt động:', error); |
| } |
| }; |
| </script> |
| </body> |
| </html> |
|
|
|
|