|
|
<!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> |
|
|
|
|
|
|